Bash就像PIPESTATUS相当于perl

时间:2015-02-09 15:46:34

标签: bash perl shell exit-code

我的目标是捕获从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(在第二种情况下bashsh的孩子)

# 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(没有模块)这是否正常

1 个答案:

答案 0 :(得分:0)

系统的返回值必须向右移动8,如perldoc says。像:

perl -e 'my $code = system("false | true"); print $? >> 8 . "\n"'