我正试图绕过IPC :: Run以便能够执行以下操作。有关文件列表:
my @list = ('/my/file1.gz','/my/file2.gz','/my/file3.gz');
我想执行一个内置解压缩的程序,对它们进行一些编辑和过滤,并打印到stdout,给stderr一些统计信息:
~/myprogram options $file
我想将列表中所有文件的执行stdout附加到一个$ out文件中,并且能够将每个stderr中的几行作为变量进行解析和存储,同时将其余部分写出来分别为每个输入文件的fileN.log文件。 我希望stdout全部进入“>> $ 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 }; }
有什么想法吗?
答案 0 :(得分:3)
首先要做的事情。 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 from命令被送到内联子程序。还修复了一个愚蠢的错字(语法是伪代码而不是Perl)。