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

58

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

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

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

Теги:
stdout
exit-code

6 ответов

25
Лучший ответ

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

  • 1
    Я не знаю, почему ссылки облажались. Все выглядит хорошо в редактировании / предпросмотре.
  • 2
    Я отправил perl5porters патч для IPC :: Open2 и :: Open3, чтобы показать материал ожидания в ОПИСАНИИ этих модулей. :)
41

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

  • 12
    Похоже, что Capture :: Tiny новее и лучше: «Этот модуль был вдохновлен IO :: CaptureOutput, который предоставляет аналогичные функциональные возможности без возможности использовать вывод и более сложный код и API. IO :: CaptureOutput не обрабатывает слои или большинство необычных случаев, описанных в разделе «Ограничения», и я больше не рекомендую его ». - search.cpan.org/~dagolden/Capture-Tiny-0.18/lib/Capture/…
  • 0
    См. Stackoverflow.com/a/8781408/110126 для примера использования Capture :: Tiny.
Показать ещё 1 комментарий
14

Если вы не хотите содержимое 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.

Все самое лучшее,

Пол

  • 0
    Технически, у него есть зависимость, но только в Windows, где требуется Win32 :: Process. Хотя это не ядро Perl, оно связано с дистрибутивами ActiveState Perl и Strawberry Perl.
  • 0
    +1, я все время использую IPC :: System :: Simple.
7

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

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 |");

Код возврата всегда сохраняется в $?, как отмечено @Майкл Карман.

  • 0
    Не забудьте qx//
0

Я нашел 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);
0

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню