Ansgar
Ansgar

Reputation: 371

Why do bash calculations return 1 if the result is zero

I'm doing simple calculations in bash and I noticed that bash calculations using expr return 1 if the result of the calculation is zero.

user@machine:~$ expr 42 - 40 ; echo $?
2
0

user@machine:~$ expr 42 - 84 ; echo $?
-42
0

user@machine:~$ expr 42 - 42 ; echo $?
0
1

Why does bash do this? Isn't a return value of 1 an indication that the program failed? Doesn't this behaviour violate good practice?

I'm doing some calculations inside a script run with set -e. What is the best way to account for the return value of 1? I could do

expr $var1 - $var2 || true

but this would also ignore other exit codes than 1.

Upvotes: 0

Views: 409

Answers (1)

chepner
chepner

Reputation: 531275

This is just the mapping of integers (as Boolean values, 0=False, 1=True) to shell exit codes (0=Success, >0=Failure). Note that "failure" does not necessarily mean "program experienced an error and/or crashed". Other programs do similar things:

* `grep` exits with 0 if a match is made, 1 if no match is made. 
* `test` exits 0 if its condition is true, 1 if its condition is false.

In C, you can use the result of an arithmetic expression directly as the condition of an if or while statement.

In shell, such statements test the exit code of a command, treating success as analogous to true and failure as analogous to false. In this sense, expr ... is short for test ... -ne 0.

In a typical language, you write something like

# Python
n = 10
while n - 3:   # short for n > 3
    ...

expr performs arithmetic, so it makes sense for the exit status to allow the same.

n=10
while expr "$n" - 3; do
    ...
done

Note that you can still detect actual errors, as opposed to Boolean falseness, by checking if the exit status of expr is greater than 1.

n=10
while true; do    # "Infinite" loop
    expr "$n" - 3
    case $? of
       1)  break ;;
       2)  echo "Error with expr" >&2; break ;;
    esac

    ...
done

Upvotes: 1

Related Questions