Perl IPC :: Запуск добавления вывода и анализа stderr, сохраняя его в пакете файлов - PullRequest
1 голос
/ 21 июня 2011

Я пытаюсь обернуть голову вокруг IPC :: Run, чтобы иметь возможность сделать следующее. Для списка файлов:

my @list = ('/my/file1.gz','/my/file2.gz','/my/file3.gz');

Я хочу запустить программу, которая имеет встроенную распаковку, выполняет некоторые операции редактирования и фильтрации к ним и печатает на стандартный вывод, предоставляя некоторую статистику для stderr:

~/myprogram options $file

Я хочу добавить стандартный вывод выполнения для всех файлов в списке в один отдельный файл $ out и иметь возможность анализировать и сохранять несколько строк в каждом stderr как переменные, в то же время позволяя выписывать остальные в отдельные файлы fileN.log для каждого входного файла. Я хочу, чтобы stdout all вошел в ">> $ all_into_one_single_out_file", это ошибка, которую я хочу сохранить в разных журналах.

После прочтения руководства я дошел до следующего кода, где комментируемая часть не знаю, как это сделать:

for $file in @list {
  my @cmd;
  push @cmd, "~/myprogram options $file";
  IPC::Run::run \@cmd, \undef, ">>$out", 
    sub { 
      my $foo .= $_[0]; 
      #check if I want to keep my line, save value to $mylog1 or $mylog2
      #let $foo and all the other lines be written into $file.log
    };
}

Есть идеи?

1 Ответ

3 голосов
/ 21 июня 2011

обо всем по порядку.my $foo .= $_[0] не обязательно.$foo - это новое (пустое) значение, поэтому добавление к нему через .= ничего не делает.Что вам действительно нужно, так это простой my ($foo) = @_;.

Далее, вы хотите, чтобы выходные данные переходили в один конкретный файл для каждой команды, а также (в зависимости от некоторых условий) помещали те же выходные данные в общий файл.

Perl (среди других языков) имеет прекрасную возможность помочь в таких проблемах, и это называется закрытием.Какие бы переменные ни находились в области действия во время определения подпрограммы, эти переменные доступны для использования.

use strict;
use warnings;

use IPC::Run qw(run new_chunker);

my @list           = qw( /my/file1 /my/file2 /my/file3 );

open my $shared_fh, '>', '/my/all-stdout-goes-here' or die;
open my $log1_fh, '>', '/my/log1' or die "Cannot open /my/log1: $!\n";
open my $log2_fh, '>', '/my/log2' or die "Cannot open /my/log2: $!\n"; 

foreach my $file ( @list ) {
  my @cmd = ( "~/myprogram", option1, option2, ..., $file );

  open my $log_fh, '>', "$file.log"
      or die "Cannot open $file.log: $!\n";

  run \@cmd, '>', $shared_fh,
             '2>', new_chunker, sub {
      # $out contains each line of stderr from the command
      my ($out) = @_;
      if ( $out =~ /something interesting/ ) {
          print $log1_fh $out;
      }
      if ( $out =~ /something else interesting/ ) {
          print $log2_fh $out;
      }
      print $log_fh $out;
      return 1;
    };
}

Каждый из дескрипторов выходного файла закроется, когда на них больше не будет ссылаться что-либо -- в данном случае в конце этого фрагмента.

Я исправил ваш @cmd, хотя я не знаю, каким будет ваш option1, option2, ....

Я также изменил способ, которым вы звоните run.Вы можете вызвать его с помощью простого >, чтобы сказать, что следующая вещь предназначена для вывода, а new_chunker (из IPC :: Run) будет разбивать ваш вывод на одну строку за раз вместо получения всехвывод все сразу.

Я также пропустил тот факт, что вы выводите файлы .gz.Если вы хотите записывать в сжатые файлы, вместо того, чтобы открывать как:

open my $fh, '>', $file  or die "Cannot open $file: $!\n";

Просто откройте:

open my $fh, '|-', "gzip -c > $file"  or die "Cannot startup gzip: $!\n";

Будьте осторожны, поскольку это хорошее место для ввода команд (например,пусть $file будет /dev/null; /sbin/reboot. Как это сделать, дано во многих, многих других местах и ​​выходит за рамки того, что вы на самом деле просите.

EDIT: перечитайте проблему немногои изменил ответ, чтобы более точно отразить действительную проблему.

EDIT2:: обновлено в соответствии с вашим комментарием. Все stdout отправляются в один файл, а команда stderr из команды подается во встроенную подпрограмму. Также исправленоглупая опечатка (для синтаксиса был псевдокод не Perl).

...