Reputation: 3280
I have a bash script that I use to execute multiple commands in sequence and I need to return non-zero exit code if at least one command in the sequence returns non-zero exit code. I know there is a wait
command for that but I'm not sure I understand how to use it.
UPD The script looks like this:
#!/bin/bash
command1
command2
command3
All the commands run in foreground. All the commands need to run regardless of which exit status the previous command returned (so it must not behave as "exit on first error"). Basically I need to gather all the exit statuses and return global exit status accordingly.
Upvotes: 59
Views: 30412
Reputation: 436
If you wish to know which command failed:
#!/bin/bash
EXITCODE_RESULT=0
command1
EXIT_CODE_1=$?
command2
EXIT_CODE_2=$?
command3
EXIT_CODE_3=$?
for i in ${!EXIT_CODE_*}
do
# check if the values of the EXIT_CODE vars contain 1
EXITCODE_RESULT=$(($EXITCODE_RESULT || ${!i}))
if [ ${!i} -ne 0 ]
then
var_fail+="'$i' "
else
var_succ+="'$i' "
fi
done
In $var_fail you get a list of the failed EXIT_CODE vars and in $var_succ a list of the successful ones
Upvotes: 0
Reputation: 2357
If you wish to know which command failed, but not neccessarily its return code you could use:
#!/bin/bash
rc=0;
counter=0;
command1 || let "rc += 1 << $counter"; let counter+=1;
command2 || let "rc += 1 << $counter"; let counter+=1;
command3 || let "rc += 1 << $counter"; let counter+=1;
exit $rc
This uses bit shifting in bash in order to set the bit corresponding to which command failed.
Hence if the first command failed you'll get an return code of 1 (=2^0), if the third failed you would get a return code of 8 (=2^3), and if both the first and the third command failed you would get 9 as the return code.
Upvotes: 4
Reputation: 85883
If by sequence you mean pipe then you need to set pipefail
in your script like set -o pipefail
. From man bash
:
The return status of a pipeline is the exit status of the last command, unless the pipefail option is enabled. If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully. If the reserved word ! precedes a pipeline, the exit status of that pipeline is the logical negation of the exit status as described above. The shell waits for all commands in the pipeline to terminate before returning a value.
If you just mean sequential commands then just check the exit status of each command and set a flag if the exit status is none zero. Have your script return the value of the flag like:
#!/bin/bash
EXIT=0
grep -q A <<< 'ABC' || EXIT=$? # Will exit with 0
grep -q a <<< 'ABC' || EXIT=$? # Will exit with 1
grep -q A <<< 'ABC' || EXIT=$? # Will exit with 0
echo $EXIT # Will print 1
exit $EXIT # Exit status of script will be 1
This uses the logical operator OR ||
to only set EXIT
if the command fails. If multiple commands fail the exit status from the last failed command will be return by the script.
If these commands are not running in the background then wait
isn't relevant here.
Upvotes: 11
Reputation: 28981
Just do it:
EXIT_STATUS=0
command1 || EXIT_STATUS=$?
command2 || EXIT_STATUS=$?
command3 || EXIT_STATUS=$?
exit $EXIT_STATUS
Not sure which of the statuses it should return if several of commands have failed.
Upvotes: 65