19

I have a bash script that sets -e so the script will exit on any exit status != 0.

I'm trying to do some basic shell arithmetic assigned to variables and sometimes the expression equals 0 which causes the exit status of the let or expr command to be "1".

Here's an example:

#!/bin/bash -ex
echo "Test 1"
Z=`expr 1 - 1` || true
echo "Z will print"
let "A=4 - 4"
echo "A WILL NEVER PRINT $A"
Y=`expr 1 - 1`
echo "Y WILL NEVER PRINT $Y"
X=$(expr 2 - 2)
echo "X WILL NEVER PRINT $X"

The output is:

$ ./test_error.sh 
+ echo 'Test 1'
Test 1
++ expr 1 - 1
+ Z=0
+ true
+ echo 'Z will print'
Z will print
+ let 'A=4 - 4'

My question is what's the idiomatic bash scripting way to allow the script to fail on real exit errors and not on basic arithmetic equaling 0. I could suffix all those expressions with:

A=`expr $C - $D`    || true

But that seems hacky.

15

Don't use expr for arithmetic. It has long been obsolete: shells now have arithmetic built in, with the $((…)) construct (POSIX), or with let builtin (ksh/bash/zsh) or the ((…)) construct (ksh/bash/zsh).

let and ((…)) return 1 (a failure status code) if the last evaluated expression is 0. To avoid this causing your script to exit under set -e, arrange for the last expression not to return 0, for example:

let "a = 2 - 2" 1
((a = 2 - 2, 1))

Alternatively, use the || true idiom:

((a = 2 - 2)) || true

Alternatively, do your arithmetic inside $((…)) and your assignments outside. An assignment returns the status of the last command substitution in the value, or 0 if there is no command substitution, so you're safe. This has the added benefit of working in any POSIX shell (such as dash).

a=$((2 - 2))
1

Use $(( $C - $D )) instead for your arithmatic. It's more efficient too.

  • What makes it more efficient than say (( A = $C - $D ))? – bishop Jan 26 '17 at 16:11
1

I had the same problem. tl;dr:

If the last ARG [of let] evaluates to 0, let returns 1; let returns 0 otherwise.

1

This syntax works for me:

a=$((b + c))

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.