Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to tell if any command in bash script failed (non-zero exit status)

I want to know whether any commands in a bash script exited with a non-zero status.

I want something similar to set -e functionality, except that I don't want it to exit when a command exits with a non-zero status. I want it to run the whole script, and then I want to know that either:

a) all commands exited with exit status 0
-or-
b) one or more commands exited with a non-zero status


e.g., given the following:

#!/bin/bash

command1  # exits with status 1
command2  # exits with status 0
command3  # exits with status 0

I want all three commands to run. After running the script, I want an indication that at least one of the commands exited with a non-zero status.

like image 234
Rob Bednark Avatar asked Feb 14 '17 04:02

Rob Bednark


People also ask

How do you check exit status in bash?

To check the exit code we can simply print the $? special variable in bash. This variable will print the exit code of the last run command.

How do you check if the last command executed was not successful in bash?

Now, every command run in bash shell returns a value that's stored in the bash variable “$?”. To get the value, run this command. $ echo $? If a command succeeded successfully, the return value will be 0.

How do you exit a script if command fails?

Exit When Any Command Fails This can actually be done with a single line using the set builtin command with the -e option. Putting this at the top of a bash script will cause the script to exit if any commands return a non-zero exit code.

What is non-zero exit status?

A non-zero exit status indicates failure. This seemingly counter-intuitive scheme is used so there is one well-defined way to indicate success and a variety of ways to indicate various failure modes. When a command terminates on a fatal signal whose number is N , Bash uses the value 128+ N as the exit status.


Video Answer


3 Answers

Set a trap on ERR:

#!/bin/bash

err=0
trap 'err=1' ERR

command1
command2
command3
test $err = 0 # Return non-zero if any command failed

You might even throw in a little introspection to get data about where the error occurred:

#!/bin/bash
for i in 1 2 3; do
        eval "command$i() { echo command$i; test $i != 2; }"
done

err=0
report() {
        err=1
        echo -n "error at line ${BASH_LINENO[0]}, in call to "
        sed -n ${BASH_LINENO[0]}p $0
} >&2
trap report ERR

command1
command2
command3
exit $err
like image 144
William Pursell Avatar answered Sep 30 '22 21:09

William Pursell


You could try to do something with a trap for the DEBUG pseudosignal, such as

trap '(( $? && ++errcount ))' DEBUG

The DEBUG trap is executed

before every simple command, for command, case command, select command, every arithmetic for command, and before the first command executes in a shell function

(quote from manual).

So if you add this trap and as the last command something to print the error count, you get the proper value:

#!/usr/bin/env bash

trap '(( $? && ++errcount ))' DEBUG

true
false
true

echo "Errors: $errcount"

returns Errors: 1 and

#!/usr/bin/env bash

trap '(( $? && ++errcount ))' DEBUG

true
false
true
false

echo "Errors: $errcount"

prints Errors: 2. Beware that that last statement is actually required to account for the second false because the trap is executed before the commands, so the exit status for the second false is only checked when the trap for the echo line is executed.

like image 25
Benjamin W. Avatar answered Sep 30 '22 22:09

Benjamin W.


I am not sure if there is a ready-made solution for your requirement. I would write a function like this:

function run_cmd_with_check() {
  "$@"
  [[ $? -ne 0 ]] && ((non_zero++))
}

Then, use the function to run all the commands that need tracking:

run_cmd_with_check command1
run_cmd_with_check command2
run_cmd_with_check command3
printf "$non_zero commands exited with non-zero exit code\n"

If required, the function can be enhanced to store all failed commands in an array which can be printed out at the end.


You may want to take a look at this post for more info: Error handling in Bash

like image 36
codeforester Avatar answered Sep 30 '22 21:09

codeforester