进入 grep -v 时获取退出代码
Get exit code when piping into grep -v
我有这样的脚本:
#!/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
并且仍然可以正确传播状态代码?当然,在现实世界中,这样做的目的是过滤嘈杂命令的输出,同时仍然检测命令是否失败。
利用 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 中所述,如果最后一个命令出错,管道通常只会 return 失败(非零 return 代码)。如果管道中的任何命令出错,使用 set -o pipefail
会导致命令管道产生失败 return 代码。管道传递的失败 return 代码是 last 失败命令的 return 代码。
您可以通过将脚本更新为:
来对此进行测试
#!/bin/sh
echo "hello"
echo "goodbye"
exit 5
然后 运行 以下内容:
( set -o pipefail; ./fail.sh | grep -v hello ); echo $?
它应该输出:
goodbye
5
以上说明 set -o pipefail
不仅以非零 return 代码退出,而且它正在逐字中继最后一个非零 return 代码。
bash
基本上只会给你管道中第一个进程的退出代码。您有两个选择:
您可以使用进程替换:
grep -v hello <(./fail.sh)
您可以利用 bash
特定的 $PIPESTATUS
变量:
./fail.sh | grep -v hello
if [ ! "${PIPESTATUS[1]}" ] ; then
echo "Foo bar!"
fi
我有这样的脚本:
#!/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
并且仍然可以正确传播状态代码?当然,在现实世界中,这样做的目的是过滤嘈杂命令的输出,同时仍然检测命令是否失败。
利用 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 中所述,如果最后一个命令出错,管道通常只会 return 失败(非零 return 代码)。如果管道中的任何命令出错,使用 set -o pipefail
会导致命令管道产生失败 return 代码。管道传递的失败 return 代码是 last 失败命令的 return 代码。
您可以通过将脚本更新为:
来对此进行测试#!/bin/sh
echo "hello"
echo "goodbye"
exit 5
然后 运行 以下内容:
( set -o pipefail; ./fail.sh | grep -v hello ); echo $?
它应该输出:
goodbye
5
以上说明 set -o pipefail
不仅以非零 return 代码退出,而且它正在逐字中继最后一个非零 return 代码。
bash
基本上只会给你管道中第一个进程的退出代码。您有两个选择:
您可以使用进程替换:
grep -v hello <(./fail.sh)
您可以利用 bash
特定的 $PIPESTATUS
变量:
./fail.sh | grep -v hello
if [ ! "${PIPESTATUS[1]}" ] ; then
echo "Foo bar!"
fi