管道输入grep -v时获取退出代码

时间:2016-05-09 23:24:50

标签: bash grep exit-code

我有一个这样的脚本:

#!/bin/sh

echo "hello"
echo "goodbye"
exit 1

当我自己运行它时,我会得到失败的退出代码。

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

但是,当我通过grep -v运行时,退出状态会变为成功:

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

有没有办法将命令的输出传递到grep -v并且仍然可以正确传播状态代码?当然,在现实世界中,重点是过滤噪声命令的输出,同时仍然检测命令是否失败。

2 个答案:

答案 0 :(得分:2)

利用set -o pipefail,以下内容应该有效:

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

然后,您可以在$?中测试值:

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

应输出:

goodbye
success

发生了什么,为什么会这样?

如OP中所述,如果最后一个命令错误,管道通常只返回一个失败(非零返回码)。如果管道中的任何命令错误,则使用set -o pipefail会导致命令管道生成失败返回码。管道传递的失败返回码是 last 失败命令的返回码。

您可以通过将脚本更新为:

来测试
#!/bin/sh

echo "hello"
echo "goodbye"
exit 5

然后执行以下操作:

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

应输出:

goodbye
5

上面说明set -o pipefail不只是以非零返回码退出,而是逐字传递最后一个非零返回码。

答案 1 :(得分:2)

bash基本上只会为您提供管道中第一个进程的退出代码。您有两种选择:

您可以使用流程替换

grep -v hello <(./fail.sh)

您可以使用bash特定$PIPESTATUS变量:

./fail.sh | grep -v hello
if [ ! "${PIPESTATUS[1]}" ] ; then
    echo "Foo bar!"
fi