16

I need to depend on few separate executions in a script and don't want to bundle them all in an ugly 'if' statement. I would like to take the exit code '$?' of each execution and add it; at the end, if this value is over a threshold - I would like to execute a command.

Pseudo code:

ALLOWEDERROR=5

run_something
RESULT=$?
..other things..

run_something_else
RESULT=$RESULT + $?

if [ $RESULT -gt ALLOWEDERROR ] 
   then echo "Too many errors"
fi

Issue: Even though the Internet claims otherwise, bash refuses to treat the RESULT and $? as integer. What is the correct syntax?

Thanks.

1
  • result=$(( result + $? )) Commented Jun 11, 2019 at 18:59

7 Answers 7

22

A quick experiment and dip into bash info says:

declare -i RESULT=$RESULT + $?

since you are adding to the result several times, you can use declare at the start, like this:

declare -i RESULT=0

true
RESULT+=$?
false
RESULT+=$?
false
RESULT+=$?

echo $RESULT
2

which looks much cleaner.

declare -i says that the variable is integer.

Alternatively you can avoid declare and use arithmetic expression brackets:

RESULT=$(($RESULT+$?))
Sign up to request clarification or add additional context in comments.

3 Comments

The last one only counts the number of times it's executed, regardless of error (or success): RESULT=$(($RESULT+1)). If you want to use the $(()) construct, you need to add $? instead of 1 (as in Dave Hinton's answer). Otherwise, you'll be incrementing even when the command returns 0. Or you can use a trap as in my answer.
Thanks for that, I've edited in your fix. I like your answer.
This won't work if one line has a return code of -1 and another has a return code of 1, since they'll add together to look like success (which is 0).
19

You might want to take a look at the trap builtin to see if it would be helpful:

help trap

or

man bash

you can set a trap for errors like this:

#!/bin/bash

AllowedError=5

SomeErrorHandler () {
    (( errcount++ ))       # or (( errcount += $? ))
    if  (( errcount > $AllowedError ))
    then
        echo "Too many errors"
        exit $errcount
    fi
}

trap SomeErrorHandler ERR

for i in {1..6}
do
    false
    echo "Reached $i"     # "Reached 6" is never printed
done

echo "completed"          # this is never printed

If you count the errors (and only when they are errors) like this instead of using "$?", then you don't have to worry about return values that are other than zero or one. A single return value of 127, for example, would throw you over your threshold immediately. You can also register traps for other signals in addition to ERR.

Comments

2

Use the $(( ... )) construct.

$ cat st.sh
RESULT=0
true
RESULT=$(($RESULT + $?))
false
RESULT=$(($RESULT + $?))
false
RESULT=$(($RESULT + $?))
echo $RESULT
$ sh st.sh
2
$

Comments

1

As mouviciel mentioned collecting sum of return codes looks rather senseless. Probably, you can use array for accumulating non-zero result codes and check against its length. Example of this approach is below:

#!/bin/sh

declare RESULT
declare index=0
declare ALLOWED_ERROR=1

function write_result {
    if [ $1 -gt 0 ]; then
        RESULT[index++]=$1
    fi
}

true
write_result $?

false
write_result $?

false
write_result $?

echo ${#RESULT[*]}
if [ ${#RESULT[*]} -gt $ALLOWEDERROR ] 
   then echo "Too many errors"
fi

Comments

1

For how to add numbers in Bash also see:

help let 

Comments

1

If you want to use ALLOWEDERROR in your script, preface it with a $, e.g $ALLOWEDERROR.

Comments

0

Here are some ways to perform an addition in bash or sh:

RESULT=`expr $RESULT + $?`
RESULT=`dc -e "$RESULT $? + pq"`

And some others in bash only:

RESULT=$((RESULT + $?))
RESULT=`bc <<< "$RESULT + $?"` 

Anyway, exit status on error is not always 1 and its value does not depend on error level, so in the general case there is not much sense to check a sum of statuses against a threshold.

4 Comments

I'd give you a +1 for the "not always 1" part of your answer, but I won't because a) you use back ticks instead of $() and b) expr is unnecessary in bash and 3) dc is way overkill for addition. If the OP were using sh instead of bash (or if it was for portability) then expr and back ticks would be OK.
...and d) why not have RESULT=bc <<< "$RESULT + $?" ?
There's never a reason to use expr in any shell compliant with even the original 1991 version of the POSIX sh specification. $(( ... )) has been available as much faster, more efficient, built-in syntax that doesn't require forking off a subprocess and exec()'ing an external command for decades now.
...which is to say, $(( ... )) is absolutely not bash-only; it works in every standards-compliant /bin/sh.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.