Setting pipefail for a single piped command
I need to execute a number of piped shell commands from a non-BASH script (namely PHP script) like these:
command1 | command2 | command3
so that, if command1
fails with a non-zero exit code, each other command fails too. So far, what I've come up with is:
set -o pipefail && command1 | command2 | command3
But even though it runs fine from the terminal, it produces this if executed from the script:
sh: 1: set: Illegal option -o pipefail
From the Bash command line you would need to invoke a subshell to avoid pipefail
being set afterwards:
$ (set -o pipefail && command1 | command2 | command3)
This would limit the effect of the pipefail
option to the subshell create by the parentheses (...)
.
A real example:
$ (set -o pipefail && false | true) && echo pipefail inactive || echo pipefail active
pipefail active
If you use an explicit shell call with the -c
option you do not need a subshell, either with bash
or with an sh
alias to bash
:
$ bash -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
$ sh -c "set -o pipefail && false | true" && echo pipefail inactive || echo pipefail active
pipefail active
Since your sh
does not accept the pipefail
option, I would have to assume that it is either some older or modified version of bash
- or that it is actually some other shell completely.
Not sure why it wasn't mentioned above, but it is possible to explicitly unset pipefail
, using set +o pipefail
.
set -o pipefail
command1 | command2 | command3
set +o pipefail
If you are executing a fragment, and unsure about the pipefail
already set, you can use this with the subshell as previously suggested:
# explicitly execute with pipefail set
(set -o pipefail ; command1 | command2 | command3 )
# explicitly execute with pipefail unset
(set +o pipefail ; command1 | command2 | command3 )