Perl IPC::Run 附加输出并解析标准错误,同时将其保存在一批文件中

Posted

技术标签:

【中文标题】Perl IPC::Run 附加输出并解析标准错误,同时将其保存在一批文件中【英文标题】:Perl IPC::Run appending output and parsing stderr while keeping it in a batch of files 【发布时间】:2011-06-21 14:23:26 【问题描述】:

我正试图围绕 IPC::Run 进行以下操作。文件列表:

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

我想执行一个内置解压的程序,对它们进行一些编辑和过滤,然后打印到 stdout,给 stderr 一些统计信息:

~/myprogram 选项 $file

我想将列表中所有文件的执行标准输出附加到一个 $out 文件中,并且能够在每个标准错误中解析和存储几行作为变量,同时让其余的被写出为每个输入文件分成单独的 fileN.log 文件。 我希望标准输出都进入“>>$all_into_one_single_out_file”,这是我想保留在不同日志中的错误。

阅读手册后,我已经走到了下面的代码,其中注释部分我不知道该怎么做:

@list 中的 $file 我的@cmd; push @cmd, "~/myprogram options $file"; IPC::运行::运行 \@cmd, \undef, ">>$out", 子 我的 $foo .= $_[0]; #检查我是否想保留我的线路,将值保存到 $mylog1 或 $mylog2 #let $foo 和所有其他行被写入 $file.log ;

有什么想法吗?

【问题讨论】:

IPC::Run::run@cmd 参数不是命令列表,它是单个命令的参数列表。如果要运行多个后台进程,请多次调用IPC::Run::run @mob:啊,谢谢,我已经相应地改写了我的问题 【参考方案1】:

首先要做的事情。 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;
    ;

当不再被任何东西引用时,每个输出文件句柄都将被关闭——在这种情况下,在这个 sn-p 的末尾。

我修复了你的@cmd,虽然我不知道你的option1option2,...会是什么。

我还更改了您呼叫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::根据您的评论更新。所有的标准输出都进入一个文件,命令中的标准错误被馈送到内联子例程。还修正了一个愚蠢的错字(因为语法是伪代码而不是 Perl)。

【讨论】:

hmmm,ifs 正在查看 stdout,我想查看 stderr。我希望标准输出都进入“>>$all_my_out_file”,这是我想保留在不同日志中的错误。有什么想法吗?

以上是关于Perl IPC::Run 附加输出并解析标准错误,同时将其保存在一批文件中的主要内容,如果未能解决你的问题,请参考以下文章

Perl:使用 IPC::Run 进行 I/O 重定向

对 perl IPC::Run 感到困惑

perl open:如何将标准错误转发到标准输出? [复制]

Perl基础命令---文件句柄基础

如何在 Perl 中捕获输出和退出代码时执行外部脚本?

如何在现代 Linux 上的 Perl 中运行程序(超时)并知道它是如何结束的(信号、退出代码等)?