Skip to content
Advertisement

bash pipefail still running w/ set -e after command in process substitution fails

script.sh:

set -x
set -e
set -u
set -o pipefail

foo=$(tail -1 <(false || { >&2 echo "failed" && exit 1; }) | echo "pipeline still running" || { >&2 echo "failed" && exit 1; }) || { >&2 echo "failed" && exit 1; }

echo "Script still running..."

Why does echo "Script still running..." end up being executed? I thought the combination of set -e and set -o pipefail should mean that false gets propagated out to the main script and terminates at foo=... but instead foo is assigned “pipeline still running”… and the script continues when I wish it would not. I had thought this question supports that idea.

After reading the bash man page about pipefail (in particular), it states that A pipeline is a sequence of one or more commands separated by one of the control operators ‘|’ or ‘|&’.

I take it, then, that set does not propagate into subshells? Is there a way to have that occur?

For reference, I am using

$ bash --version
GNU bash, version 4.3.46(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Advertisement

Answer

Nothing to do with pipefail.

cat <(exit 1)

…has an exit status of 0, with or without pipefail set: Process substitutions are not pipeline components, and their exit status is not checked.

That said, in bash 4.4 and later you can check it explicitly as follows:

cat <(exit 1); pid=$!
wait "$pid" # this will have the exit status of the process substitution operation

Incidentally, there are compelling reasons for this. Consider:

exec 3< <(echo hello; exit 1)
read greeting <&3
echo "Greeting is: $greeting"

Now, which command would you expect to fail? It can’t be the one where the redirection from a process substitution is actually performed, because the process substitution remains active beyond that single command’s execution, and until a read has occurred, the process substitution hasn’t failed yet.

It wouldn’t reliably be read greeting, because that read succeeds — it’s only after the write associated with that read has completed that the process on the other end of the pipeline fails, and it’s not guaranteed that that exit has or has not happened before the outer shell has gone on to the final echo.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement