Bash as the PIPESTATUS equivalent for perl

My goal is to grab the exit code of an external command issued from perl. The trick is that the external team consists of two teams, where the first team is transferred to the second team. For my purposes, I need the exit code of the first command. Bash uses several possible ways to do this , for example.

$ false | true; echo "${PIPESTATUS[0]}"
1
$ true | false; echo "${PIPESTATUS[0]}"
0

      

After reading this issue, I found that the perl command system

can get the process termination code, so I tried the following:

$ 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

      

As you can see, I am getting strange return codes (256, 512, 2560) from the command system

. I think this is related to my other question . So far, the only possible way I could get the return code of the first command is by using qw

or backtickss ``. This seems a little overkill to me, as I need echo

to fix the value 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

      

I am also wondering why this approach even works because it mentions here that perl does not invoke a shell to execute an external command. So where does it come from PIPESTATUS

(which is a pure Bash variable)? Also I would expect the following command to work, since Bash is explicitly issued but returns nothing:

$ perl -e 'my $res = `bash -c "false | true 2>&1 >/dev/null; echo \${PIPESTATUS[0]}"`; print $res'

$

      

The third understanding of the error is based on this answer, that I can access a variable directly by PIPESTATUS

assigning it to a variable and then getting it as a regular perl variable like

status=(${PIPESTATUS[@]})
print $status

      

However, the following command doesn't work for me.

$ 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 in response to ThisSuitIsBlackNot, tjd and CapEnt

Return codes and bit shift explained:

$ 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

      

Some systems have /bin/sh

indicating 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

      

some don't ...

# 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

      

a bit of a hack to use bash

, no matter what points out /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

      

Here you can see that in both cases Bash is called ( bash

there are children in the second case 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

      

As pointed out in this example, probably the best solution is to use IPC :: Run , but I'm wondering if it's okay if I want pure perl (no modules)

+1


source to share


1 answer


The system return value should be shifted by 8 while perldoc says . How:



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

      

0


source







All Articles