¿Cómo capturar stderr, stdout y el código de salida de una sola vez en Perl?

¿Es posible ejecutar un proceso externo desde Perl, capturar su stderr, stdout Y el código de salida del proceso?

Me parece ser capaz de hacer combinaciones de estos, por ejemplo, utilizar los trazos atrás para obtener stdout, IPC :: Open3 para capturar salidas, y system () para obtener los códigos de salida.

¿Cómo captura stderr, stdout y el código de salida de una sola vez?

Si vuelve a leer la documentación de IPC :: Open3, verá una nota que debe llamar a waitpid para obtener el proceso secundario. Una vez que haga esto, el estado debería estar disponible en $? . El valor de salida es $? >> 8 $? >> 8 . Ver $? en perldoc perlvar .

( Actualización : actualicé la API para IO :: CaptureOutput para hacer esto aún más fácil).

Hay varias formas de hacer esto. Aquí hay una opción, usando el módulo IO :: CaptureOutput :

 use IO::CaptureOutput qw/capture_exec/; my ($stdout, $stderr, $success, $exit_code) = capture_exec( @cmd ); 

Esta es la función capture_exec (), pero IO :: CaptureOutput también tiene una función de captura () más general que se puede utilizar para capturar la salida Perl o la salida de progtwigs externos. Entonces, si algún módulo de Perl utiliza algún progtwig externo, aún obtendrá la salida.

También significa que solo necesita recordar un enfoque único para capturar STDOUT y STDERR (o fusionarlos) en lugar de usar IPC :: Open3 para progtwigs externos y otros módulos para capturar resultados de Perl.

Si no quiere los contenidos de STDERR, entonces el comando capture () del módulo IPC :: System :: Simple es casi exactamente lo que busca:

  use IPC::System::Simple qw(capture system $EXITVAL); my $output = capture($cmd, @args); my $exit_value = $EXITVAL; 

Puede usar capture () con un solo argumento para invocar el shell o varios argumentos para evitar el shell de manera confiable. También hay capturex () que nunca llama al shell, incluso con un solo argumento.

A diferencia de los comandos incorporados del sistema y de los backticks de Perl, IPC :: System :: Simple devuelve el valor de salida completo de 32 bits en Windows. También arroja una excepción detallada si el comando no puede iniciarse, muere a una señal o devuelve un valor de salida inesperado. Esto significa que para muchos progtwigs, en lugar de verificar los valores de salida usted mismo, puede confiar en IPC :: System :: Simple para que haga el trabajo por usted:

  use IPC::System::Simple qw(system capture $EXIT_ANY); system( [0,1], "frobincate", @files); # Must return exitval 0 or 1 my @lines = capture($EXIT_ANY, "baznicate", @files); # Any exitval is OK. foreach my $record (@lines) { system( [0, 32], "barnicate", $record); # Must return exitval 0 or 32 } 

IPC :: System :: Simple es Perl puro, no tiene dependencias y funciona tanto en sistemas Unix como Windows. Desafortunadamente, no proporciona una forma de capturar STDERR, por lo que puede no ser adecuado para todas sus necesidades.

IPC :: Run3 proporciona una interfaz limpia y fácil para volver a conectar las tres manejadoras de archivos comunes, pero desafortunadamente no verifica si el comando fue exitoso, ¿por lo que necesitará inspeccionar $? manualmente, lo cual no es para nada divertido. ¿Proporciona una interfaz pública para inspeccionar $? es algo que está en mi lista de cosas por hacer para IPC :: System :: Simple, desde la inspección de $? en una plataforma multiplataforma no es una tarea que desearía a nadie.

Hay otros módulos en el espacio de nombres IPC :: que también pueden proporcionarle asistencia. YMMV.

Todo lo mejor,

Pablo

Hay tres formas básicas de ejecutar comandos externos:

 system $cmd; # using system() $output = `$cmd`; # using backticks (``) open (PIPE, "cmd |"); # using open() 

Con system() , tanto STDOUT como STDERR irán al mismo lugar que STDOUT y STDERR, menos que el comando system() redirija. Backticks y open() solo leen el STDOUT de su comando.

También puede llamar a algo como lo siguiente con abierto para redirigir STDOUT y STDERR .

 open(PIPE, "cmd 2>&1 |"); 

El código de retorno siempre se almacena en $? como lo señaló @Michael Carman .

Si te estás volviendo realmente complicado, quizás quieras probar Expect.pm. Pero eso probablemente sea excesivo si no necesita administrar el envío de entradas al proceso también.

Encontré IPC: run3 para ser muy útil. Puede reenviar todas las tuberías secundarias a un globo o a una variable; ¡muy facilmente! Y el código de salida se almacenará en $ ?.

A continuación se muestra cómo agarré stderr, que sabía que sería un número. El cmd dio como resultado transformaciones informáticas a stdout (que canalicé a un archivo en args usando>) e informó cuántas transformaciones a STDERR.

 use IPC::Run3 my $number; my $run = run3("cmd arg1 arg2 >output_file",\undef, \undef, \$number); die "Command failed: $!" unless ($run && $? == 0); 
Intereting Posts