Perl: código de erro retornado para open3 após o programa morto

0

Este programa mostra qual erro é retornado para open3 ao executar sleep 3 ou true;sleep 3 e sleep é eliminado:

#!/bin/bash                                                                                                           
doit() {
  shell="$1"
  prg="$2"
  (sleep 2 && killall sleep) &
  perl -MIPC::Open3 -e 'open3($a,$b,$c,"'$shell'","-c","'"$prg"'"); wait; print $?>>8,"\n"'
}
export -f doit
parallel -j1 --tag doit \
  ::: ash bash csh dash fdsh fish fizsh ksh ksh93 mksh posh rc sash sh static-sh tcsh yash zsh \
  ::: '/bin/sleep 3' 'true;/bin/sleep 3'

No meu sistema, ele fornece:

ash /bin/sleep 3        143
ash true;/bin/sleep 3   143
bash /bin/sleep 3       0
bash true;/bin/sleep 3  143
csh /bin/sleep 3        143
csh true;/bin/sleep 3   143
dash /bin/sleep 3       143
dash true;/bin/sleep 3  143
fdsh /bin/sleep 3       143
fdsh true;/bin/sleep 3  143
fish /bin/sleep 3       143
fish true;/bin/sleep 3  143
fizsh /bin/sleep 3      143
fizsh true;/bin/sleep 3 143
ksh /bin/sleep 3        0
ksh true;/bin/sleep 3   0
ksh93 /bin/sleep 3      0
ksh93 true;/bin/sleep 3 0
mksh /bin/sleep 3       0
mksh true;/bin/sleep 3  143
posh /bin/sleep 3       143
posh true;/bin/sleep 3  143
rc /bin/sleep 3 1
rc true;/bin/sleep 3    1
sash /bin/sleep 3       255
sash true;/bin/sleep 3  0
sh /bin/sleep 3 143
sh true;/bin/sleep 3    143
static-sh /bin/sleep 3  143
static-sh true;/bin/sleep 3     143
tcsh /bin/sleep 3       143
tcsh true;/bin/sleep 3  143
yash /bin/sleep 3       0
yash true;/bin/sleep 3  0
zsh /bin/sleep 3        0
zsh true;/bin/sleep 3   0

Todos os programas que retornam 143 eu posso explicar. Mas o que causa os outros valores de erro? Estou especialmente intrigado com bash , o que dá dois valores diferentes.

    
por Ole Tange 27.10.2017 / 23:46

1 resposta

2

Para o

bash /bin/sleep 3       0

podemos observar isso com strace

$ strace -f -e trace=process bash -c 'sleep 1'
execve("/usr/bin/bash", ["bash", "-c", "sleep 1"], [/* 22 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7ffff7fe3740) = 0
execve("/usr/bin/sleep", ["sleep", "1"], [/* 22 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7ffff7fe3740) = 0
exit_group(0)                           = ?
+++ exited with 0 +++
$ 

que, sem nenhum sinal TERM , mostra que bash se substitui por sleep ; por contraste, o composto true;sleep 3 form mostrará um clone (se no Linux), já que bash irá forçar o sleep e manipular o código de saída.

Com um SIGTERM envolvido, vemos:

$ strace -f -e trace=process bash -c 'sleep 999'
execve("/usr/bin/bash", ["bash", "-c", "sleep 999"], [/* 22 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7ffff7fe3740) = 0
execve("/usr/bin/sleep", ["sleep", "999"], [/* 22 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7ffff7fe3740) = 0
--- SIGTERM {si_signo=SIGTERM, si_code=SI_USER, si_pid=3896, si_uid=0} ---
+++ killed by SIGTERM +++
$ echo $?
143
$ 

Isso nos leva ao código Perl, que é incorreto; em Perl $? representa a palavra de status de 16 bits de wait(2) , e não qualquer valor que um shell tenha manipulado essa palavra de status de 16 bits. Seu print $?>>8 imprime somente as informações do código de saída, que para um sinal é de fato 0. Se, em vez disso, uma inspeção correta do conteúdo de $? for usada:

#!/usr/bin/env perl
use 5.14.0;
use warnings;
use IPC::Open3 qw(open3);

my ( $input, $output, $err );
open3( $input, $output, $err, qw(bash -c), "sleep 999" );
wait;

if ( $? == -1 ) {
    say "noexec $!";
} elsif ( $? & 127 ) {
    printf "died signal=%d core=%s\n",
                 ( $? & 127 ), ( $? & 128 ) ? 'yea' : 'nay';
} else {
    say "exit ", $? >> 8;
}

Em seguida, o Perl apresentará um relatório para o caso de bash -c 'sleep 3' kill corretamente:

$ perl ipcopenfoo
died signal=15 core=nay
$ 
    
por 28.10.2017 / 01:09