我正在编写一个目前有以下内容的脚本:
my @files = `$some_command`;
print @files;
chomp @files;
foreach my $file (@files)
{
process($file);
}
它可以正常工作,但some_command
部分占用了脚本的大部分时间。在此期间,stdout上没有任何内容,因为Perl已将some_command
的输出重定向到填充@files
数组。它仅在some_command
完成后打印,Perl移至print @files;
。
是否有一些聪明的方法来更改此代码,以便some_command
的输出在执行时出现?我可以使用tee(1)
尝试这样的事情:
my $tmpfile = File::Temp->new();
system("$some_command | tee " . $tmpfile->filename);
my @files;
{ local $/ = undef; @files = split /\s/, <$tmpfile>; }
但如果有更简单的解决方案,我宁愿避免使用临时文件。
答案 0 :(得分:5)
您可以打开手柄并在打印线条时自己手动填充阵列。
这样的事可能会奏效,
open my $fh, '-|', $some_command;
while(<$fh>)
{
print $_;
push @files, $_;
}
close $fh;
答案 1 :(得分:2)
您可以跳过qx()
运算符并直接打开进程输出流的文件句柄。此代码在功能上等同于my @files = qx($some_command)
:
my @files = ();
open my $proc_fh, "$some_command |";
while (<$proc_fh>) {
push @files, $_;
}
close $proc_fh;
但在while循环中,您可以使用$_
执行任何操作:
while (<$proc_fh>) {
print "INPUT: $_\n";
push @files, $_;
}
一个重要的考虑因素是$some_command
的输出缓冲行为。如果该命令缓冲其输出,那么在有大量数据可用之前,$proc_fh
句柄将不会收到任何输入。
答案 2 :(得分:1)
File::Tee
模块看起来可以做你想要的。有些例子在运行system()
时重定向STDOUT。我没有用它,所以我不能给出更具体的例子,但看起来这对你来说是一个很好的起点。
答案 3 :(得分:1)
您还可以将命令作为文件描述符打开,并在命令生成时读取输出。这样的事情(取自http://www.netadmintools.com/art269.html):
#!/usr/bin/perl
open (PINGTEST, "/bin/ping -c 5 netadmintools.com |");
$i=1;
while (<PINGTEST>){
print "Line # ".$i." ".$_;
$i++;
}
print "All done!\n";
close PINGTEST;
答案 4 :(得分:1)
Capture::Tiny可能就是你想要的。
use Capture::Tiny qw/ tee tee_merged /;
($stdout, $stderr) = tee {
# your code here
};
$merged = tee_merged {
# your code here
};