"set -e" in shell and command substitution

Ivan Tarasov picture Ivan Tarasov · Dec 30, 2010 · Viewed 8.2k times · Source

In shell scripts set -e is often used to make them more robust by stopping the script when some of the commands executed from the script exits with non-zero exit code.

It's usually easy to specify that you don't care about some of the commands succeeding by adding || true at the end.

The problem appears when you actually care about the return value, but don't want the script to stop on non-zero return code, for example:

output=$(possibly-failing-command)
if [ 0 == $? -a -n "$output" ]; then
  ...
else
  ...
fi

Here we want to both check the exit code (thus we can't use || true inside of command substitution expression) and get the output. However, if the command in command substitution fails, the whole script stops due to set -e.

Is there a clean way to prevent the script from stopping here without unsetting -e and setting it back afterwards?

Answer

SiegeX picture SiegeX · Dec 30, 2010

Yes, inline the process substitution in the if-statement

#!/bin/bash

set -e

if ! output=$(possibly-failing-command); then
  ...
else
  ...
fi

Command Fails

$ ( set -e; if ! output=$(ls -l blah); then echo "command failed"; else echo "output is -->$output<--"; fi )
/bin/ls: cannot access blah: No such file or directory
command failed

Command Works

$ ( set -e; if ! output=$(ls -l core); then echo "command failed"; else echo "output is: $output"; fi )
output is: -rw------- 1 siegex users 139264 2010-12-01 02:02 core