Skip to content
Advertisement

“mkdir || echo && exit” exiting even when mkdir succeeds

mkdir $2 || echo “I can’t create directory $2” && exit 8

Hi everyone, this is my first post here, so be kind.

I am making a script right now and this line troubles me.

The exit 8 should happen only if the directory $2 cannot be created. After running the script and successfully creating that directory, it still exits on 8.

Am I missing something? I thought the command after ” || ” happens only if you get a false on the left side.

I am new to the Linux world, and as a guy with a little to medium C experience I am confused, help! (using ubuntu, bash, btw)

Advertisement

Answer

As @fernand0 suggested, the problem is the precedence of the || and && operators. You want it to run something like mkdir || ( echo && exit ) — that is, run the echo && exit part if mkdir fails. But what it’s actually doing is running something like ( mkdir || echo ) && exit — that is, it runs the exit part if either the mkdir OR echo command succeeds. echo will almost always succeed, so it’ll almost always exit.

So, you need to explicitly group the commands, to override this precedence. But don’t use ( ), because that runs its contents in a subshell, and exit will just exit the subshell, not the main script; you can use { } instead, or use an explicit if block. Also, you don’t actually want echo && exit, because that runs exit only if the echo command succeeds. echo almost always succeeds, but in the rare case that it fails I’m pretty sure you want the script to exit anyway.

When I need to do something like this in a script, I usually use this idiom:

mkdir "$2" || {
    echo "I can't create directory $2" >&2
    exit 8
}

(Note: as @CharlesDuffy suggested, I added double-quotes around $2 — double-quoting variable references is almost always a good idea in case they contain any spaces, wildcards, etc. I also sent the error message to standard error (>&2) instead of standard output, which is also generally a better way to do things.)

If you want to be terser, you can put it all on one line:

mkdir "$2" || { echo "I can't create directory $2" >&2; exit 8; }

Note that the final ; (or a line break) is required before the }, or the shell thinks } is just an argument to exit. You could also go the other way and use an explicit if block:

if ! mkdir "$2"; then
    echo "I can't create directory $2" >&2
    exit 8
fi

This option is less clever and concise, but that’s a good thing — clever and concise is exactly what caused this problem in the first place; clear and unambiguous is much better for code.

Advertisement