Aborting a Shell Script If Any Command Returns a Non-Zero Value

Aborting a shell script if any command returns a non-zero value

Add this to the beginning of the script:

set -e

This will cause the shell to exit immediately if a simple command exits with a nonzero exit value. A simple command is any command not part of an if, while, or until test, or part of an && or || list.

See the bash(1) man page on the "set" internal command for more details.

I personally start almost all shell scripts with "set -e". It's really annoying to have a script stubbornly continue when something fails in the middle and breaks assumptions for the rest of the script.

Exiting a shell-script at the end with a non-zero code if any command fails

One possible way would be to catch the non-zero exit code via trap with ERR. Assuming your tests don't contain pipelines | and just return the error code straight to the shell launched, you could do

#!/usr/bin/env bash

exitCodeArray=()

onFailure() {
exitCodeArray+=( "$?" )
}

trap onFailure ERR

# Add all your tests here

addNumbers () {
local IFS='+'
printf "%s" "$(( $* ))"
}

Add your tests anywhere after the above snippet. So we keep adding the exit code to the array whenever a test returns a non-zero return code. So for the final assertion we check if the sum of the array elements is 0, because in an ideal case all cases should return that if it is successful. We reset the trap set before

trap '' ERR

if (( $(addNumbers "${exitCodeArray[@]}") )); then
printf 'some of your tests failed\n' >&2
exit -1
fi

How to exit from shell script if any of the command in SSH returns non-zero value

Keep in mind that your set -e idea applies just as well to the shell you open on the other end with ssh. So you can prepend your ssh commands with that to ensure an error terminates the ssh session:

$SSH $user@$remoteIpAddress "set -e; sudo rm -rf $remoteLocation/xxx/*; cd $remoteLocation/yyy; .... ... "

Then the ssh shell will exit with non-zero error code as soon as an error is encountered, and your script will exit as well if you have set -e earlier in your script.

How can I make a shell script exit when any command in it fails?

Putting && between commands will tell bash to execute commands from start to end, and if any fail along the way, it will stop executing.

For example:

echo $(non_existent_variable) && cd ~

cd ~ is a valid command. However, since non_existent_variable is not defined, the first command fails and an error is thrown immediately.

In your case, you can add && \ at the end of each of your lines.

Automatically exit when bash command produce return code non zero

There are lots of problems with using set -e. Just join the commands with &&, and test the result with an if statement.

if cd /something_something && mv file_a /somedir/file_a; then
echo $?
exit
fi
echo "Both cd and mv worked"

Bash Script - If Pyscript Returns Non-zero, Write Errors to Output File AND Quite Bash Script

The exit status of a pipeline is the status of the last command, so $? is the status of tee, not pytest.

In bash you can use the $PIPESTATUS array to get the status of each command in the pipeline.

python3 run_tests.py 2>&1 | tee tests.log
status=${PIPESTATUS[0]} # status of run_tests.py
if [ $status -ne 0 ]; then
echo 'ERROR: pytest failed, exiting ...'
exit $status
fi

Note that you need to save the status in another variable, because $? and $PIPESTATUS are updated after each command.

non-zero value of 2 numbers with a return exit code in shell

You want to return two exit codes at the same time? I guess that, when driving a car, you also want to sit on the front seat and on the back seat at the same time. You can do it, but you need a special car for this. Here are two ideas for making such a car:

  • If you know that in this context each exit code must be a 1-digit number, you could return something like $((RC*10+RC2)) - I'm using bash/zsh syntax here, as you didn't say which shell you are using. If necessary, you have to adapt this to your shell.

  • You could adapt the interface of your script, by printing something like "$RC1 $RC2" to stderr if at least one of them is non-zero, i.e.:

    if [ $RC -ne 0 ] || [ $RC1 -ne 0 ]; then
    echo "$RC $RC1" 1>&2
    exit 1
    else
    exit 0
    fi

In both cases, the calling process has to take apart the combined exit code to get back the original ones.

Exit Shell Script Based on Process Exit Code

After each command, the exit code can be found in the $? variable so you would have something like:

ls -al file.ext
rc=$?; if [[ $rc != 0 ]]; then exit $rc; fi

You need to be careful of piped commands since the $? only gives you the return code of the last element in the pipe so, in the code:

ls -al file.ext | sed 's/^/xx: /"

will not return an error code if the file doesn't exist (since the sed part of the pipeline actually works, returning 0).

The bash shell actually provides an array which can assist in that case, that being PIPESTATUS. This array has one element for each of the pipeline components, that you can access individually like ${PIPESTATUS[0]}:

pax> false | true ; echo ${PIPESTATUS[0]}
1

Note that this is getting you the result of the false command, not the entire pipeline. You can also get the entire list to process as you see fit:

pax> false | true | false; echo ${PIPESTATUS[*]}
1 0 1

If you wanted to get the largest error code from a pipeline, you could use something like:

true | true | false | true | false
rcs=${PIPESTATUS[*]}; rc=0; for i in ${rcs}; do rc=$(($i > $rc ? $i : $rc)); done
echo $rc

This goes through each of the PIPESTATUS elements in turn, storing it in rc if it was greater than the previous rc value.



Related Topics



Leave a reply



Submit