Consider the following code

outer-scope.sh

#!/bin/bash
set -e
source inner-scope.sh
echo $(inner)
echo "I thought I would've died :("

inner-scope.sh

#!/bin/bash
function inner() { echo "winner"; return 1; }

I'm trying to get outer-scope.sh to exit when a call to inner() fails. Since $() invokes a sub-shell, this doesn't happen.

How else do I get the output of a function while preserving the fact that the function may exit with a non-zero exit code?

link|improve this question

50% accept rate
feedback

2 Answers

up vote 3 down vote accepted

$() preserves the exit status; you just have to use it in a statement that has no status of its own, such as an assignment.

output=$(inner)

After this, $? would contain the exit status of inner, and you can use all sorts of checks for it:

output=$(inner) || exit $?
echo $output

Or:

if ! output=$(inner); then
    exit $?
fi
echo $output

Or:

if output=$(inner); then
    echo $output
else
    exit $?
fi

(Note: A bare exit without arguments is equivalent to exit $? – that is, it exits with the last command's exit status. I used the second form only for clarity.)


Also, for the record: source is completely unrelated in this case. You can just define inner() in the outer-scope.sh file, with the same results.

link|improve this answer
Why is it that, even though $? contains the exit status of $() that the script does not exit automatically (given that -e is set)? EDIT: nevermind, I think you have answered my questions, thanks! – jabalsad Dec 2 '11 at 16:12
I'm not sure. (I haven't tested any of the above.) But there are some restrictions on -e, all explained in bash's manpage; also, if you are asking about echo $(), then it might be because the subshells' exit codes are ignored when the line - the echo command - has an exit code (usually 0) of its own. – grawity Dec 2 '11 at 18:10
feedback
#!/bin/bash
set -e
source inner-scope.sh
foo=$(inner)
echo $foo
echo "I thought I would've died :("

By adding echo, the subshell does not stand alone (is not separately checked) and does not abort. Assignment circumvents this problem.

You can also do this, and redirect the output to a file, to later process it.

tmpfile=$( mktemp )
inner > $tmpfile
cat $tmpfile
rm $tmpfile
link|improve this answer
Of course, the $tmpfile continues to exist in the second variant... – Daniel Beck Dec 1 '11 at 13:43
feedback

Your Answer

 
or
required, but never shown

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