问题
I have a piped command such as:
set -euxo pipefail
echo 'hello' | foo | touch example.sh
This is the output:
$ set -euxo pipefail
$ echo hello
$ foo
$ touch example.sh
pipefail.sh: line 4: foo: command not found
I thought set -e
would cause the script to exit however. But even though foo
is unrecognized, the script is still executing the touch
command. How do I get it to exit if foo
fails?
回答1:
You can't really think of a pipeline of having "earlier" or "later" parts, except insofar as data moves through them from one end to the other: All parts of a pipeline run at the same time.
Consequently, you can't prevent later parts from starting if an earlier part failed, because the later part started at the same time the earlier part did.
The above being said, there are mechanisms to allow a pipeline to shut down early in the event of a failure -- mechanisms which work the same way without needing to set any non-default shell flags at all:
- If you're using a tool designed to be used on the right-hand side of a pipeline (unlike
touch
), it will be reading from stdin -- and will thus see an early EOF should the components to the left of it fail. - If you're using a tool designed to be used on the left-hand side of a pipeline, it will receive a
SIGPIPE
when it attempts to write if the thing to the right of it is no longer running.
Of course, these mechanisms don't work if you're piping from a program that doesn't write to stdout, or into a program that doesn't read from stdin -- but such programs don't make much sense to use in pipelines anyhow.
来源:https://stackoverflow.com/questions/51957772/can-i-stop-later-parts-of-a-pipeline-from-running-if-an-earlier-part-failed