我的目标是捕获从perl发出的外部命令的退出代码。诀窍是外部命令实际上由两个命令组成,其中第一个命令通过管道输出到第二个命令。为了我的目的,我需要第一个命令的退出代码。 Bash用于此目的several possible方式,例如。
$ false | true; echo "${PIPESTATUS[0]}"
1
$ true | false; echo "${PIPESTATUS[0]}"
0
在阅读了这个有问题的内容后,我发现perl system
命令能够获取进程的退出代码,所以我尝试了以下内容:
$ exit 10 | true
$ echo ${PIPESTATUS[0]}
10
$ true | false
$ echo $?
1
$ perl -e 'my $code = system("true | false"); print $code . "\n"'
256
$ perl -e 'my $code = system("bash -c \"true | false\""); print $code . "\n"'
256
$ perl -e 'my $code = system("bash -c \"exit 2\""); print $code . "\n"'
512
$ perl -e 'my $code = system("bash 2>&1 >/dev/null"); print $code . "\n"'
$ exit 10
exit
2560
正如您所见,我从system
命令获得了奇怪的返回码(256,512,2560)。我认为这与我的另一个question有关。到目前为止,我能够访问第一个命令的返回码的唯一可能方法是使用qw
或backtickss``。这似乎对我来说有点过分,因为我需要一个echo
来捕获PIPESTATUS[0]
值。
$ perl -e 'my $res = qx/true | false 2>&1 >\/dev\/null; echo \${PIPESTATUS[0]}/; print $res'
0
$ perl -e 'my $res = qx/false | true 2>&1 >\/dev\/null; echo \${PIPESTATUS[0]}/; print $res'
1
$ perl -e 'my $res = qx"false | true 2>&1 >/dev/null; echo \${PIPESTATUS[0]}"; print $res'
1
$ perl -e 'my $res = qx"true | false 2>&1 >/dev/null; echo \${PIPESTATUS[0]}"; print $res'
0
$ perl -e 'my $res = qx(false | true 2>&1 >/dev/null; echo \${PIPESTATUS[0]}); print $res'
1
$ perl -e 'my $res = `false | true 2>&1 >/dev/null; echo \${PIPESTATUS[0]}`; print $res'
1
我也想知道为什么这种方法甚至有效,因为提到here perl不会调用shell来执行外部命令。那么PIPESTATUS
(纯粹的bash变量)来自何处呢?此外,我希望以下命令可以工作,因为bash是显式发出的,但它什么都不返回:
$ perl -e 'my $res = `bash -c "false | true 2>&1 >/dev/null; echo \${PIPESTATUS[0]}"`; print $res'
$
第三个错误理解基于this答案,我可以通过将变量分配给变量来直接访问PIPESTATUS
变量,然后作为常规perl变量进行访问,例如。
status=(${PIPESTATUS[@]})
print $status
但是以下命令对我不起作用。
$ perl -e 'my $res = `false | true 2>&1 >/dev/null;`; status=(${PIPESTATUS[@]})'
syntax error at -e line 1, near "@]}"
Missing right curly or square bracket at -e line 1, at end of line
Execution of -e aborted due to compilation errors.
@EDIT 回复ThisSuitIsBlackNot,tjd和CapEnt
返回代码和位移说明:
$ perl -e 'my $code = system("true | false"); print $code >> 8; print "\n"'
1
$ perl -e 'my $code = system("bash -c \"true | false\""); print $code >> 8; print "\n"'
1
$ perl -e 'my $code = system("bash -c \"exit 2\""); print $code >> 8; print "\n"'
2
某些系统/bin/sh
指向bash
...
# Linux arch 3.18.6-1-ARCH #1 SMP PREEMPT Sat Feb 7 08:59:29 CET 2015 i686 GNU/Linux
$ ls -la `which sh`
lrwxrwxrwx 1 root root 4 Dec 30 23:11 /usr/bin/sh -> bash
$ perl -e 'my $cmd = "exit 255 | true 2>&1 >/dev/null; echo \${PIPESTATUS[0]}"; system($cmd);'
255
有些人不是......
# SunOS andromeda 5.9 Generic_122300-61 sun4u sparc SUNW,Sun-Fire-V490
$ ls -la `which sh`
-r-xr-xr-x 4 root root 95504 Jul 16 2009 /bin/sh
$ perl -e 'my $cmd = "exit 255 | true 2>&1 >/dev/null; echo \${PIPESTATUS[0]}"; system($cmd);'
sh: bad substitution
一个使用bash
的小黑客,无论/bin/sh
指向的是什么:
# Linux arch 3.18.6-1-ARCH #1 SMP PREEMPT Sat Feb 7 08:59:29 CET 2015 i686 GNU/Linux
# SunOS andromeda 5.9 Generic_122300-61 sun4u sparc SUNW,Sun-Fire-V490
$ perl -e 'my $cmd = "bash -c \"exit 255 | true 2>&1 >/dev/null; echo \\\${PIPESTATUS[0]}\""; system($cmd);'
255
在这里你可以看到在两种情况下调用bash(在第二种情况下bash
是sh
的孩子)
# Linux arch 3.18.6-1-ARCH #1 SMP PREEMPT Sat Feb 7 08:59:29 CET 2015 i686 GNU/Linux
$ perl -e 'my $code = system("bash -c \"ps -elf | grep $$\"");'
0 S wakatana 1576 282 0 80 0 - 1606 wait 16:46 pts/1 00:00:00 perl -e my $code = system("bash -c \"ps -elf | grep $$\"");
0 S wakatana 1577 1576 0 80 0 - 1333 wait 16:46 pts/1 00:00:00 bash -c ps -elf | grep 1576
0 S wakatana 1579 1577 0 80 0 - 1167 pipe_w 16:46 pts/1 00:00:00 grep 1576
# SunOS andromeda 5.9 Generic_122300-61 sun4u sparc SUNW,Sun-Fire-V490
$ perl -e 'my $code = system("bash -c \"ps -elf | grep $$\"");'
8 S wakatana 24641 24640 0 60 20 ? 314 ? 16:01:45 pts/196 0:00 bash -c ps -elf | grep 24639
8 S wakatana 24640 24639 0 50 20 ? 139 ? 16:01:45 pts/196 0:00 sh -c bash -c "ps -elf | grep 24639
8 S wakatana 24643 24641 0 50 20 ? 128 ? 16:01:45 pts/196 0:00 grep 24639
8 S wakatana 24639 24633 0 50 20 ? 383 ? 16:01:45 pts/196 0:00 perl -e my $code = system("bash -c
由于ThisSuitIsBlack没有指出,可能最好的解决方案是使用IPC::Run,但我想知道如果我需要纯perl(没有模块)这是否正常
答案 0 :(得分:0)
系统的返回值必须向右移动8,如perldoc says。像:
perl -e 'my $code = system("false | true"); print $? >> 8 . "\n"'