Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get exit code when piping into grep -v [duplicate]

I have a script like this:

#!/bin/sh

echo "hello"
echo "goodbye"
exit 1

When I run it on its own, I get the failed exit code as I expect.

$ ./fail.sh
hello
goodbye
$ echo $?
1

However, when I run it through grep -v, the exit status changes to success:

$ ./fail.sh | grep -v hello
goodbye
$ echo $?
0

Is there a way to pipe a command's output into grep -v and still have the status code be properly propagated? Of course in the real world the point of this would be to filter the output of a noisy command, while still detecting if the command failed.

like image 207
limp_chimp Avatar asked Jan 06 '23 02:01

limp_chimp


2 Answers

Leveraging set -o pipefail, the following should work:

( set -o pipefail; ./fail.sh | grep -v hello )

You can then test the value in $?:

( set -o pipefail; ./fail.sh | grep -v hello ); if [[ "$?" -eq "1" ]]; then echo success; else echo bummer; fi 

It should output:

goodbye
success

What is happening and why does this work?

As noted in the OP, pipelines normally only return a failure (non-zero return code) if the last command errors. Using set -o pipefail causes a pipeline of commands to produce a failure return code if any command in the pipeline errors. The failure return code that the pipeline passes is the return code of the last failed command.

You can test this by updating your script to:

#!/bin/sh

echo "hello"
echo "goodbye"
exit 5

then run the following:

( set -o pipefail; ./fail.sh | grep -v hello ); echo $?

It should output:

goodbye
5

The above illustrates that set -o pipefail is not just exiting with a non-zero return code but that it is relaying the last non-zero return code verbatim.

like image 127
John Mark Mitchell Avatar answered Jan 17 '23 02:01

John Mark Mitchell


bash will basically just give you the exit code of the last process in the pipe but you can use the bash specific $PIPESTATUS variable:

./fail.sh | grep -v hello
if [ ! "${PIPESTATUS[0]}" ] ; then
    echo "command has failed"
fi
like image 35
hek2mgl Avatar answered Jan 17 '23 01:01

hek2mgl