lucacerone
lucacerone

Reputation: 10149

bash execute whole script but return exit code > 0 if any intermediate job has failed

I have a bash script script.sh made like:

./step1.sh
./step2.sh
./step3.sh

Each of the step*.h scripts returns proper error codes whether they failed or not.

Now if step3.sh fails I get an appropriate exit code, but if either step1.sh or step2.sh fails and step3.sh succeeds than I get status = 0, which is not ideal.

I know I can use

set -e

at the top of my script to make the script fail if any of the intermediate steps fail, but that is not what I want.

I would like to know if there is an easy option to use to execute each of the intermediate scripts (even if one of them fails) but return an exit code > 0 if any of them fails without having to keep track of each individual exit code manually.

Upvotes: 5

Views: 2253

Answers (4)

Jacek Trociński
Jacek Trociński

Reputation: 920

You can trap errors:

#!/bin/bash

echo "test start."

trap 'rc=$?' ERR

./error.sh
./script2.sh

echo "test done."
return ${rc} 

For more information on how traps work, see trap.

Upvotes: 5

tripleee
tripleee

Reputation: 189908

Boiling down to the absolute basics,

rc=0
./step1 || rc=$?
./step2 || rc=$?
./step3 || rc=$?
exit $rc

Upvotes: 1

paxdiablo
paxdiablo

Reputation: 882606

I know you stated you didn't want to have to maintain every exit code but that's actually pretty easy to do with arrays:

declare -a rcs
./step1.sh ; rcs+=($?)
./step2.sh ; rcs+=($?)
./step3.sh ; rcs+=($?)

Then you can simply step through the array in a loop, looking for the first (or largest, last, average, sum, etc) error code to do with as you wish. The code below shows how to do this to return the first error encountered:

for ((idx = 0; idx < ${#rcs[@]}; idx++)); do
    [[ ${rcs[$idx]} -ne 0 ]] && return ${rcs[$idx]}
done
return 0

Similarly, to get the largest error:

rc=0
for ((idx = 0; idx < ${#rcs[@]}; idx++)); do
    [[ ${rcs[$idx]} -gt $rc ]] && rc=${rcs[$idx]}
done
return $rc

Upvotes: 0

anubhava
anubhava

Reputation: 786091

You can do like this:

#!/bin/bash

# array with all the scripts to be executed
arr=(./step1.sh ./step2.sh ./step3.sh)

# initialize return status to 0
ret=0

# run a loop to execute each script
for i in "${arr[@]}"; do

   echo "running $i"
   bash "$i"
   ret=$((ret | $?)) # return status from previous step bitwise OR with current status

done

echo "exiting with status: $ret"

exit $ret

Upvotes: 0

Related Questions