zig*_*don 2 perl pipe exit-code
我有一个使用如下命令运行的perl脚本:
/path/to/binary/executable | /path/to/perl/script.pl
Run Code Online (Sandbox Code Playgroud)
该脚本对二进制文件的输出执行有用的操作,然后在STDIN用完后退出(<>返回undef).除非二进制文件以非零代码退出,否则这一切都很好.从脚本的POV开始,它认为脚本刚刚结束,所以它清理并退出,代码为0.
有没有办法让perl脚本看到退出代码是什么?理想情况下,我想要这样的东西工作:
# close STDIN, and if there was an error, exit with that same error.
unless (close STDIN) {
print "error closing STDIN: $! ($?)\n";
exit $?;
}
Run Code Online (Sandbox Code Playgroud)
但不幸的是,这似乎不起作用:
$ (date; sleep 3; date; exit 1) | /path/to/perl/script.pl /tmp/test.out
Mon Jun 7 14:43:49 PDT 2010
Mon Jun 7 14:43:52 PDT 2010
$ echo $?
0
Run Code Online (Sandbox Code Playgroud)
有没有办法让它做我的意思?
编辑添加:
perl脚本实时操作二进制命令的输出,因此将其全部缓冲到文件中是不可行的解决方案.但是,它不需要知道退出代码,直到脚本结束.
bash环境变量$PIPESTATUS
是一个数组,它包含最后一个命令管道的每个部分的状态.例如:
$ false | true; echo "PIPESTATUS: ${PIPESTATUS[@]}; ?: $?"
PIPESTATUS: 1 0; ?: 0
Run Code Online (Sandbox Code Playgroud)
所以听起来不是重构你的perl脚本,你只需要运行该管道命令的脚本来检查$PIPESTATUS
.在$PIPESTATUS
没有的情况下使用[@]
会给出数组第一个元素的值.
如果需要检查初始可执行文件和perl脚本的状态,则需要先将$ PIPESTATUS分配给另一个变量:
status=(${PIPESTATUS[@]})
Run Code Online (Sandbox Code Playgroud)
然后你可以单独检查它们,比如
if (( ${status[0]} )); then echo "main reactor core breach!"; exit 1;
elif (( ${status[1]} )); then echo "perls poisoned by toxic spill!"; exit 2;
fi;
Run Code Online (Sandbox Code Playgroud)
您必须通过临时变量执行此操作,因为下一个语句(即使它是一个if
语句)将${PIPESTATUS[@]}
在以下语句之前重置,即使它是一个elif
语句,也可以检查它.
请注意,这些东西仅适用于bash,而不适用于原始的bourne shell(通常sh
,虽然许多系统由于其向后兼容性而链接/bin/sh
到/bin/bash
).所以如果你把它放在shell脚本中,第一行应该是
#!/bin/bash
Run Code Online (Sandbox Code Playgroud)
而不是#!/bin/sh
.