¿Cómo se capturan stderr, stdout y el código de salida, todos a la vez, en Perl?
Pregunta
¿Es posible ejecutar un proceso externo desde Perl, capturar su stderr, stdout Y el código de salida del proceso?
Parece que puedo hacer combinaciones de estos, p.use comillas invertidas para obtener la salida estándar, IPC::Open3 para capturar resultados y system() para obtener códigos de salida.
¿Cómo se capturan stderr, stdout y el código de salida al mismo tiempo?
Solución
Si vuelves a leer la documentación de IPC::Open3, verás una nota a la que debes llamar esperar para cosechar el proceso hijo.Una vez hecho esto, el estado debería estar disponible en $?
.El valor de salida es $? >> 8
.Ver$?
en perldoc perlvar.
Otros consejos
(Actualizar:Actualicé la API para IO::CaptureOutput para que esto sea aún más fácil).
Hay varias formas de hacer esto.Aquí hay una opción, usando el IO::CapturaSalida módulo:
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 capture() más general que se puede utilizar para capturar la salida de Perl o la salida de programas externos.Entonces, si algún módulo Perl utiliza algún programa externo, aún obtendrá el resultado.
También significa que solo necesita recordar un único enfoque para capturar STDOUT y STDERR (o fusionarlos) en lugar de usar IPC::Open3 para programas externos y otros módulos para capturar resultados de Perl.
Si no desea el contenido de STDERR, entonces el comando capture() de IPC::Sistema::Simple El módulo es casi exactamente lo que buscas:
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 múltiples argumentos para evitar el shell de manera confiable.También está capturex() que nunca llama al shell, ni siquiera con un solo argumento.
A diferencia del sistema integrado de Perl y de los comandos de comillas invertidas, IPC::System::Simple devuelve el valor de salida completo de 32 bits en Windows.También genera una excepción detallada si el comando no se puede iniciar, muere ante una señal o devuelve un valor de salida inesperado.Esto significa para muchos programas, en lugar de verificar los valores de salida usted mismo, puede confiar en IPC :: System :: fácil de hacer el trabajo duro 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 que no sea adecuado para todas sus necesidades.
IPC::Ejecutar3 proporciona una interfaz limpia y sencilla para volver a conectar los tres identificadores de archivos comunes, pero desafortunadamente no verifica si el comando fue exitoso, por lo que deberá inspeccionar $?manualmente, lo cual no es nada divertido.Proporcionar una interfaz pública para inspeccionar $?es algo que está en mi lista de quehaceres para IPC::System::Simple, desde que inspecciona $?de forma multiplataforma no es una tarea que le desearía a nadie.
Hay otros módulos en el PCI:: espacio de nombres que también puede brindarle ayuda.YMMV.
Mis mejores deseos,
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()
, ambos STDOUT
y STDERR irá al mismo lugar que el guión. STDOUT
y STDERR,
a menos que el system()
El comando los redirige.comillas invertidas y open()
leer solo el STDOUT
de tu mando.
También puedes llamar a algo como lo siguiente con open para redirigir ambos STDOUT
y STDERR
.
open(PIPE, "cmd 2>&1 |");
El código de retorno siempre se almacena en $?
como lo señaló @Michael Carmen.
Si te estás poniendo realmente complicado, quizás quieras probar Expect.pm.Pero eso probablemente sea excesivo si no necesita administrar también el envío de entradas al proceso.
encontré IPC:ejecutar3 ser de mucha ayuda.Puede reenviar todas las canalizaciones secundarias a un globo o una variable;¡muy facilmente!Y el código de salida se almacenará en $?.
A continuación se muestra cómo tomé stderr, que sabía que sería un número.El cmd generó transformaciones informáticas a stdout (que canalicé a un archivo en los argumentos 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);