Можно ли запустить внешний процесс с Perl, записать его stderr, stdout И код выхода процесса?
Кажется, я могу сделать комбинацию из них, например. использовать backticks для получения stdout, IPC:: Open3 для захвата выходов и system() для получения кодов выхода.
Как вы одновременно захватываете stderr, stdout и код выхода?
Если вы перечитаете документацию для IPC:: Open3, вы увидите примечание, которое вы должны называть waitpid, чтобы получить ребенка обработать. После этого статус должен быть доступен в $?
. Значение выхода $? >> 8
. Видеть
$?
в perldoc perlvar.
( Обновление: я обновил API для IO:: CaptureOutput, чтобы сделать это еще проще.)
Есть несколько способов сделать это. Здесь один из вариантов, используя модуль IO::CaptureOutput:
use IO::CaptureOutput qw/capture_exec/;
my ($stdout, $stderr, $success, $exit_code) = capture_exec( @cmd );
Это функция capture_exec(), но IO:: CaptureOutput также имеет более общую функцию capture(), которая может использоваться для захвата вывода Perl или вывода из внешних программ. Поэтому, если какой-то модуль Perl использует какую-либо внешнюю программу, вы все равно получаете результат.
Это также означает, что вам нужно запомнить только один подход к захвату STDOUT и STDERR (или их слиянию) вместо использования IPC:: Open3 для внешних программ и других модулей для записи вывода Perl.
Если вы не хотите содержимое STDERR, то команда capture() из IPC::System::Simple - это почти то, re после:
use IPC::System::Simple qw(capture system $EXITVAL);
my $output = capture($cmd, @args);
my $exit_value = $EXITVAL;
Вы можете использовать capture() с единственным аргументом для вызова оболочки или несколькими аргументами, чтобы надежно избежать оболочки. Там также capturex(), который никогда не вызывает оболочку, даже с одним аргументом.
В отличие от встроенных команд Perl и backticks, IPC:: System:: Simple возвращает полное 32-разрядное значение выхода в Windows. Он также выдает подробное исключение, если команда не может быть запущена, умирает до сигнала или возвращает неожиданное значение выхода. Это означает, что для многих программ, а не для проверки значений выхода самостоятельно, вы можете положиться на IPC:: System:: Простая работа для вас:
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 - чистый Perl, не имеет зависимостей и работает как в Unix, так и в Windows. К сожалению, он не обеспечивает способ захвата STDERR, поэтому он не подходит для всех ваших потребностей.
IPC::Run3 предоставляет чистый и простой интерфейс для повторного санкционирования всех трех обычных дескрипторов файлов, но, к сожалению, он не проверяет, не команда была успешной, поэтому вам нужно будет проверить $? вручную, что совсем не весело. Предоставление открытого интерфейса для проверки $? это что-то, что находится на моем список дел для IPC:: System:: Simple, так как проверка $? в кросс-платформенной моде - это не задача, которую я бы пожелал никому.
В IPC:: есть другие модули, которые также могут помочь вам. YMMV.
Все самое лучшее,
Пол
Существует три основных способа запуска внешних команд:
system $cmd; # using system()
$output = `$cmd`; # using backticks (``)
open (PIPE, "cmd |"); # using open()
С system()
оба STDOUT
и STDERR будут находиться там же, что и script STDOUT
и STDERR,
, если команда system()
не перенаправляет их. Backticks и open()
читать только STDOUT
вашей команды.
Вы также можете вызвать что-то вроде следующего с open для перенаправления как STDOUT
, так и STDERR
.
open(PIPE, "cmd 2>&1 |");
Код возврата всегда сохраняется в $?
, как отмечено @Майкл Карман.
qx//
Я нашел IPC: run3, чтобы быть очень полезным. Вы можете пересылать все дочерние трубы в глобус или переменную; очень легко! И код выхода будет сохранен в $?.
Ниже, как я схватил stderr, который, как я знал, был бы числом. Cmd выводит информационные преобразования в stdout (которые я передал в файл в args using > ) и сообщал, сколько преобразований в STDERR.
use IPC::Run3
my $number;
my $run = run3("cmd arg1 arg2 >output_file",\undef, \undef, \$number);
die "Command failed: $!" unless ($run && $? == 0);
Если вы действительно усложняетесь, вы можете попробовать Expect.pm. Но это, вероятно, слишком велико, если вам не нужно также управлять отправкой ввода в процесс.