Как одновременно захватить stderr, stdout и код выхода в Perl?

Можно ли запустить внешний процесс из Perl, захватить его stderr, stdout И код выхода процесса?

Кажется, я могу использовать их комбинации, например используйте обратные кавычки для получения stdout, IPC :: Open3 для захвата выходных данных и system () для получения кодов выхода.

Как одновременно захватить stderr, stdout и код выхода?


person Scooby    schedule 20.09.2008    source источник


Ответы (6)


Если вы перечитаете документацию по IPC :: Open3, вы увидите примечание о том, что вам следует вызвать waitpid, чтобы получить дочерний процесс. После этого статус должен быть доступен в $?. Значение выхода $? >> 8. См. $? в perldoc perlvar.

person Michael Carman    schedule 20.09.2008
comment
Не знаю, почему лажаются ссылки. При редактировании / предварительном просмотре все выглядит нормально. - person Michael Carman; 20.09.2008
comment
Я отправил perl5porters патч для IPC :: Open2 и :: Open3, чтобы показать материал waitpid в СИНХРОНИЗАЦИИ этих модулей. :) - person brian d foy; 22.09.2008

(Обновление: я обновил 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.

person xdg    schedule 20.09.2008
comment
Похоже, что Capture :: Tiny новее и лучше: «Этот модуль был вдохновлен от IO :: CaptureOutput, который предоставляет аналогичную функциональность без возможности вывода тройника и с более сложным кодом и API. IO :: CaptureOutput не обрабатывает слои или большинство необычных случаев, описанных в разделе «Ограничения», и я больше не рекомендую это делать ». - search.cpan.org/~ dagolden / Capture-Tiny-0.18 / lib / Capture / - person Philip Durbin; 01.08.2012
comment
См. stackoverflow.com/a/8781408/110126 для примера использования Capture :: Tiny. - person buzz3791; 19.05.2014
comment
@PhilipDurbin, забавно, что автор этого ответа - тот же парень, что и автор Capture :: Tiny. :) - person simbabque; 20.04.2016

Если вам не нужно содержимое STDERR, тогда команда capture () из IPC Модуль :: System :: Simple - это почти то, что вам нужно:

   use IPC::System::Simple qw(capture system $EXITVAL);

   my $output = capture($cmd, @args);

   my $exit_value = $EXITVAL;

Вы можете использовать функцию capture () с одним аргументом для вызова оболочки или несколькими аргументами, чтобы надежно избежать оболочки. Также существует функция capturex (), которая никогда не вызывает оболочку даже с одним аргументом.

В отличие от встроенных в Perl команд system и обратных кавычек, IPC :: System :: Simple возвращает полное 32-битное значение выхода под Windows. Он также генерирует подробное исключение, если команда не может быть запущена, умирает от сигнала или возвращает неожиданное значение выхода. Это означает, что для многих программ вместо того, чтобы самостоятельно проверять значения выхода, вы можете положиться на IPC :: System :: Simple, который сделает за вас тяжелую работу:

 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.

Всего наилучшего,

Павел

person pjf    schedule 21.09.2008
comment
Технически у него есть зависимость, но только в Windows, где требуется Win32 :: Process. Хотя этого нет в ядре Perl, он входит в состав дистрибутивов ActiveState Perl и Strawberry Perl. - person xdg; 21.09.2008

Есть три основных способа запуска внешних команд:

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

С system() и STDOUT, и STDERR будут находиться в том же месте, что и STDOUT и STDERR, скрипта, если их не перенаправит команда system(). Обратные кавычки и open() читают только STDOUT вашей команды.

Вы также можете вызвать что-то вроде следующего с open для перенаправления как STDOUT, так и STDERR.

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

Код возврата всегда хранится в $?, как отметил @Michael Carman.

person hoyhoy    schedule 20.09.2008
comment
Не забывай qx// - person Nathan Fellman; 06.04.2017

Если вы действительно усложняете задачу, вы можете попробовать Expect.pm. Но это, вероятно, излишество, если вам не нужно также управлять отправкой ввода в процесс.

person skiphoppy    schedule 21.09.2008

Я обнаружил, что IPC: run3 очень полезный. Вы можете перенаправить все дочерние каналы в глобус или переменную; очень легко! А код выхода будет храниться в $ ?.

Ниже показано, как я взял stderr, который, как я знал, будет числом. Cmd выводит информационные преобразования в stdout (который я передал в файл в аргументах с помощью>) и сообщил, сколько преобразований в STDERR.

use IPC::Run3

my $number;
my $run = run3("cmd arg1 arg2 >output_file",\undef, \undef, \$number);
die "Command failed: $!" unless ($run && $? == 0);
person Ian    schedule 25.04.2012