You can't really other than using your workaround, doing:
output=$(false) echo "Evaluating $output should abort."
instead of:
echo "Evaluating $(false) should abort."
Personally, I'd stay well clear off the errexit option (and if using it, I'd rather use set -o errexit than set -e), and do proper error handling:
#! /bin/sh - die() { [ "$#" -eq 0 ] || printf>&2 '%s\n' "$@" exit 1 } filter() { # don't consider it an error if there's no matching line grep "$@" || [ "$?" -eq 1 ] } pf() { set -o pipefail; } output=(pf; cmd | filter -v string) || die "cmd or filter failed" printf>&2 'I got this output: "%s"\n' "$output" # don't care if printf fails in this case as I want to carry on regardless cmd2 || die # ...
Note that in:
set -o errexit a=$(false) b=$(true) printf '$%s: "%s"\n' a "$a" b "$b"
None of the shells I tried exit on the a=$(false). You need to make sure you write it:
a=$(false); b=$(true)
Or:
a=$(false) b=$(true)
Or without errexit:
a=$(false) && b=$(true) || die 'Some message'
Whether errexit causes exits in subshells or functions also depends on a number of factors, and on the shell and version thereof. Really, errexit is only usable in the most simple of scripts.
falseexiting with a non-zero exit status is surely not an error, andechosuccessfully outputting a string is not an error either. If thefalseis replaced bycat /tmp/nonexisting, then there is an error, and it is not swallowed (unless you throw away the error stream). However,echostill successfully outputs the string, and since it does, the shell does not terminate.