7

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?

Ivan Tarasov
  • 7,038
  • 5
  • 27
  • 23

1 Answers1

6

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
SiegeX
  • 135,741
  • 24
  • 144
  • 154
  • thanks, that works! For some reason though I get `ls: blah: No such file or directory` message twice. Any ideas why? – Ivan Tarasov Dec 30 '10 at 02:55
  • I just took your example which does `ls -l blah`, and it showed the message twice – Ivan Tarasov Dec 30 '10 at 03:00
  • @ivant hmm, I really can't say why that's happening. Out of curiosity, is the 2nd one prefixed with `output is:`? Does this happen if you change `blah` to something crazy like `as9dfasdf0afd` ? – SiegeX Dec 30 '10 at 03:05
  • It doesn't matter, what it is, as long as the file does not exist. I actually found the reason though: it prints it twice under `zsh`, once under `bash`. – Ivan Tarasov Dec 30 '10 at 03:13
  • @ivant that's very interesting. Not quite sure what would be causing `zsh` to behave that way. Good to note though – SiegeX Dec 30 '10 at 03:21
  • Tried in zsh, it is printed only once. – balki Apr 08 '14 at 15:52
  • Besides `if`, one can also make up a test for `$?` after a `||` like: `foo="$(bar)" || [ 3 -eq $? ]` – imz -- Ivan Zakharyaschev Sep 18 '17 at 11:37