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

7

3 Answers

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.

1

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 )

You can use $(command1) combined with $? :

a=$(echo "a")
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Prints "abc"

a=$(ls unexitingDir)
[ $? -eq 0 ] && b=$(echo $a"b")
[ $? -eq 0 ] && c=$(echo $b"c")
echo $c

Prints "".

"[ $? -eq 0 ] &&" means that the following command is executed only if the previous one succed.

That dosen't answer your question but it's a solution to your problem.

2

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

You Might Also Like