5

So I have a script like this:

somecommad | grep --invert-match something

I'd like to be able to conditionally run a different command if somecommand fails. Here's what I tried:

somecommand | grep --invert-match something || {
    echo 'Oops'
}

But that didn't work (the grep wasn't executed). What is the proper way to do this?

2
  • 6
    Perhaps you can use bash's PIPESTATUS array: see for example Get exit status of process that's piped to another Oct 21 at 1:22
  • When you use a pipe, grep starts before you can necessarily know if somecommand has failed or not. Do you want to the other command's output to go to grep as well? { somecommand || { echo Oops; }; } | grep ....
    – chepner
    Oct 21 at 16:11
10

@steeldriver mentioned in the comments that PIPESTATUS might work. I tried it, and it worked well. Here's what I did:

somecommand | grep --invert-match something
if [ "${PIPESTATUS[0]}" != "0" ]; then
    echo 'Oops'
fi

It runs the command as before, but then I have an if statement to look at the PIPESTATUS array. I only care about the first element, so that is the one I look at. I check it it failed (if the exit code is not 0), and it it did fail, run echo 'Oops'

3
  • Does this work regardless of set -o pipefail?
    – Pedro A
    Oct 21 at 21:58
  • @PedroA I don't know what that does. If you try it, feel free to edit my answer or post your own, though.
    – cocomac
    Oct 21 at 23:07
  • Yes it works with pipefail, but not with set -e -o pipefail as it won’t reach the if.
    – eckes
    Oct 22 at 2:33
7

Another way, depending on the exact behaviour needed, is to use the pipefail option:

The exit status of a pipeline is the exit status of the last command in the pipeline, unless the pipefail option is enabled (see The Set Builtin). If pipefail is enabled, the pipeline's return status is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands exit successfully.

So, if you don't care which of somecommand or grep failed, as long as one of those did fail:

set -o pipefail
if ! somecommand | grep --invert-match something; then
    echo 'Oops'
fi

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.