coiax
coiax

Reputation: 640

Using command substitution or similar, but still having script exit (using set -e)

Bash doesn't seem to pass the "exit on error" environment flag into command substitution shells.

I am using a large number of command substitutions (to get around bash's lack of return values), but I'd still like the whole script to go down if something in the subshell fails.

So, for example:

set -e    

function do_internet {
    curl not.valid.address
}

answer=$(do_internet)

I'd like the script to stop there and then, and not continue. (I hoped that setting -e would stop from having to put '|| die' on everything.

Am I doing something wrong; and/or is there any way around this?

Here's a little example:

#!/bin/bash

set -e

echo "You should only see this line, and not any other line."

function foo {
    false
    echo "The above line is false. Figure that one out, Plato."
}

bar=$(foo)

echo $bar

It prints both lines. (Using GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu))

Upvotes: 5

Views: 1090

Answers (1)

rici
rici

Reputation: 241841

There is a difference in handling of -e between subshells created with (...), as in Why doesn't bash flag -e exit when a subshell fails?, and subshells created with command substitution $(...), as in the OP.

According to the section COMMAND EXECUTION ENVIRONMENT in the bash manual (and slightly confusingly):

Subshells spawned to execute command substitutions inherit the value of the -e option from the parent shell. When not in posix mode, bash clears the -e option in such subshells.

Regardless of the posix setting, the -e only applies to the subshell created for the purposes of command substitution. So:

$ set -e
# The subshell has -e cleared
$ echo $(false; echo foo)
foo
$ set -o posix
# Now the subshell has -e, so it terminates at `false`
$ echo $(false; echo foo)

$

Nonetheless, -e does apply to the execution of a command which only sets a variable. So

set -e
a=$(false)

will terminate the shell.

However, -e does not apply to individual commands in a function. In the case of

fail() {
  false
  echo "failed"
}

The return value of fail is 0 (i.e. success) because the echo (which was the last command executed) succeeded. Consequently

a=$(fail) && echo ok

will set a to failed and then print ok

Upvotes: 7

Related Questions