Como posso trabalhar em torno do programa com falha se houver * qualquer * stdin?

2

Por exemplo, o seguinte funciona bem:

/usr/bin/program

Produz alguma saída e chega ao resultado.

Mas se eu invoco assim:

echo -n | /usr/bin/program

ou isto

echo -n | bash -c "/usr/bin/program"

ou até mesmo isso:

echo -n | bash -c "wc -c; /usr/bin/program"

Produz algumas linhas de saída e falha. Eu não tenho acesso a fonte do programa, então não posso nem olhar o que poderia causar esse comportamento.

E quando tento invocá-lo a partir do script python, recebo o mesmo material:

echo | python -c 'from subprocess import call; call("/usr/bin/program", shell=True)'

(a versão sem "echo" funciona antes)

Eu nem tenho a menor idéia de por que isso poderia estar acontecendo. O Stdin será aberto mesmo que eu não especifique explicitamente de onde o programa deve ler, então essa não deve ser a causa.

Existe alguma maneira de contornar esse problema?

EDITAR:

As últimas quatro linhas de strace output - as únicas que diferem:

# without echo
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
...

# with echo
select(1, [0], NULL, NULL, {0, 0})      = 1 (in [0], left {0, 0})
write(4, "
sleep 20 | /usr/bin/program
/usr/bin/program
echo -n | /usr/bin/program
j
echo -n | bash -c "/usr/bin/program"
echo -n | bash -c "wc -c; /usr/bin/program"
echo | python -c 'from subprocess import call; call("/usr/bin/program", shell=True)'
# without echo
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
select(1, [0], NULL, NULL, {0, 0})      = 0 (Timeout)
...

# with echo
select(1, [0], NULL, NULL, {0, 0})      = 1 (in [0], left {0, 0})
write(4, "
sleep 20 | /usr/bin/program
%pre%%pre%j%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%7777", 20) = 20 write(3, "%pre%%pre%%pre%j%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%7777", 20) = 20 exit_group(1) = ?
%pre%%pre%%pre%%pre%%pre%%pre%7777", 20) = 20 write(3, "%pre%%pre%%pre%j%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%%pre%7777", 20) = 20 exit_group(1) = ?

SOLUÇÃO PARCIAL:

%pre%

Parece que program espera que algo aconteça no stdin e sai se encontrar uma nova linha ou EOF (podemos ver isso de select call na saída strace - ele atinge o tempo limite se a entrada vier do usuário "real") . Então, precisávamos de um programa que não escrevesse nada para stdin, mantendo-o aberto - sleep faz o trabalho.

    
por Rogach 11.07.2013 / 19:26

1 resposta

2

Aqui está um one-liner Perl que fará o que você quiser:

perl -e '$SIG{CHLD} = sub{exit 0}; open $fh, "|-", @ARGV or die; sleep 20 while 1;' /usr/bin/program

É essencialmente o mesmo que um mítico * sleep forever | /usr/bin/program , exceto que ele também assiste ao programa terminar e sairá imediatamente quando isso acontecer. Se / usr / bin / program precisar de quaisquer args, você pode anexá-los ao final da linha.

* sleep forever não funciona, mas o GNU sleep durará para sempre se você sleep inf !

    
por 11.07.2013 / 23:12