Home > database >  Chaining OR and AND in Bash
Chaining OR and AND in Bash

Time:10-07

I would like to chain the OR and AND commands so that I print the contents of a directory to stdout if the directory exists, or in the case that it does not, print a message to stdout saying that the directory "$MY_DIR" is being created and then create it.

I have the following code.

ls "$MY_DIR" || echo "Creating $MY_DIR" && mkdir -p "$MY_DIR"

Is this the correct and canonical way to do this? Will mkdir always run since echo will return 0 return status, even in the case that ls does return?

The most relevant question I have located so far is this one which does not eliminate my doubts.

CodePudding user response:

I would not do what you are doing that way in any case. You should group your commands for clarity if for no other reason.

ls "$MY_DIR" || {
    echo "Creating $MY_DIR"
    mkdir -p "$MY_DIR"
}

This has several advantages: your intent is more clearly expressed, there is less ambiguity between what the human thinks will happen and what the computer will do, and it stops relying on the exit code from echo that you were not really interested in to begin with. Even if your original version worked entirely correctly it was more vulnerable to later, naïve modification.

A oneliner form is of course possible, if less readable:

ls "$MY_DIR" || { echo "Creating $MY_DIR"; mkdir -p "$MY_DIR"; }

As for your original method, consider this:

If the ls command fails:

false || true && echo mkdir # prints mkdir

But if the ls command succeeds

true || true && echo mkdir # also prints mkdir

Whereas

true || { true; echo mkdir; } # does not print
false || { true; echo mkdir; } # prints mkdir

It gets worse: I am not entirely clear whether ls will set an unsuccessful return code if the file/directory does not exist. It's certainly true that GNU ls does this, and it may be common, but the standard doesn't seem to say what constitutes success or failure, so implementations may well disagree.

CodePudding user response:

Why does it have to be chaining, with all the potential problems that might bring? Why not express your intentions clearly?

Also, UPPERCASE is usually reserved for environment variables.

# -d checks for directory specifically, use -e for existence.
# Thanks to @sorpigal for pointing it out.
if [[ -d $my_dir ]]
then
    ls "$my_dir"
else
    echo "Creating $my_dir"
    mkdir -p "$my_dir"
fi

Or, if it has to be one line...

if [[ -d $my_dir ]]; then ls "$my_dir"; else echo "Creating $my_dir"; mkdir -p "$my_dir"; fi
  •  Tags:  
  • bash
  • Related