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
.