Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

bash script using && not stopping on error

Tags:

bash

i have a script that I accidentally ran without an underlying file present, and my script doesn't have a check for this file, because the script should stop when the command that requires that file exits 1.

i got caught out because it went ahead and skipped the sleep command and the ||exit 0 if test that I have as some protection protection. i would really like to know why. the if test and exit works if the preceding command doesn't fail.

if i strip the script down I can see some unexpected behaviour where the script doesn't stop at the && and skips the next sleep command.

is this not the correct way to use &&?

you can test this here:

#!/bin/bash
mkdir /root/simulatecomplexcommandthatreturns1 &&
sleep 5m
echo "let's go ahead and delete all the stuff"
find /blah/ -delete

this is on debian 9

EDIT:

for clarity, I want the script to stop when it encounters an error and I have &&. I just thought it was odd that it didn't run the sleep command.

like image 842
jakethedog Avatar asked May 22 '26 15:05

jakethedog


2 Answers

The && only apply to next command, for a sequence, braces must be added:

#!/bin/bash
mkdir /root/simulatecomplexcommandthatreturns1 && {
    sleep 5m
    echo "let's go ahead and delete all the stuff"
    find /blah/ -delete
}

or to avoid indent level the condition can be inverted

#!/bin/bash
mkdir /root/simulatecomplexcommandthatreturns1 || {
    echo "something goes wrong"
    exit 1
}

# ok, continue
sleep 5m
echo "let's go ahead and delete all the stuff"
find /blah/ -delete
like image 74
Nahuel Fouilleul Avatar answered May 25 '26 18:05

Nahuel Fouilleul


If you want a script to abort/exit as soon as a command pipeline exists with a non-zero status (that means the last command in the pipeline, unless pipefail enabled), you might consider using:

set -e

In your example:

#!/bin/bash
set -e
mkdir /root/simulatecomplexcommandthatreturns1
sleep 5m
echo "let's go ahead and delete all the stuff"
find /blah/ -delete

when any of the commands fails, your script will exit.

Note however, this can sometimes lead to unwanted exits. For example it's normal for grep to exit with error if no match was found (you might "silence" such commands with grep .. || true ensuring the pipeline exits with success).

You'll probably be safer with manually testing for failure. For example:

if ! mkdir /root/simulatecomplexcommandthatreturns1; then
    echo "Error description."
    exit 1
fi

The usage of shortcircuiting && and || is best reserved for simple command sequences, when the execution of the next depends on successful exit of the previous. For example, the command pipeline:

mkdir /somedir && cp file /somedir && touch /somedir/file

will try to create a directory, if created successfully, it will try to copy the file; and if the file was copied successfully, it will touch the file.

Example with OR:

cp file /somedir || exit 1

where we try to copy the file and we exit if copy failed.

But you should be very careful when combining the two, since the result can be unexpected. For example:

a && b || c

is not equal to:

if a; then b; else c; fi

because c in the former expression will get executed whenever either of a or b fails (exits with a non-zero status). In the latter expression, c is executed only if a fails. For example:

true && false || echo "This also gets executed."
like image 35
randomir Avatar answered May 25 '26 18:05

randomir



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!