[英]capturing STDERR from commands and pipe STDOUT in perl under windows
I'm working on a Perl script that uses system to run a pipe of external commands like this: 我正在使用一个Perl脚本,它使用系统来运行一系列外部命令,如下所示:
system( "command1 | command2 | command3 > outfile" );
now I'd like to capture the STDERR from all these commands to one file. 现在我想将所有这些命令中的STDERR捕获到一个文件中。 This works in OS X:
这适用于OS X:
system( "command1 2> error.log | command2 2> error.log | command3 2> error.log > outfile" );
but not in Windows, where I get the error: 但不是在Windows中,我得到错误:
"the process cannot access the file because it is being used by another process"
“进程无法访问该文件,因为它正被另一个进程使用”
Is there any workaround? 有没有解决方法? I need this to be portable, so I'd like to avoid modules, if possible.
我需要它是便携式的,所以如果可能的话,我想避免使用模块。 Thanks in advance.
提前致谢。
No shells, no temporary files, and nothing from outside of core. 没有shell,没有临时文件,也没有来自核心之外的东西。
use strict;
use warnings;
use IPC::Open3 qw( open3 );
my @pids;
{
my @cmd1 = ( 'perl', '-E', q{say for qw( ABC DEF );} );
my @cmd2 = ( 'perl', '-pe', q{$_=lc; warn(qq{x\n});} );
my @cmd3 = ( 'perl', '-pe', q{$_=ucfirst; warn(qq{y\n});} );
my $nul = $^O eq 'MSWin32' ? 'nul' : '/dev/null';
open(local *CHILD_STDIN, '<', $nul ) or die $!;
open(local *CHILD_STDOUT, '>', 'outfile' ) or die $!;
open(local *CHILD_STDERR, '>', 'error.log') or die $!;
push @pids, open3('<&CHILD_STDIN', local *PIPE1, '>&CHILD_STDERR', @cmd1);
push @pids, open3('<&PIPE1', local *PIPE2, '>&CHILD_STDERR', @cmd2);
push @pids, open3('<&PIPE2', '>&CHILD_STDOUT', '>&CHILD_STDERR', @cmd3);
*CHILD_STDIN if 0; # Silence warning. Already closed by open3.
*PIPE1 if 0; # Silence warning. Already closed by open3.
*PIPE2 if 0; # Silence warning. Already closed by open3.
close(CHILD_STDOUT);
close(CHILD_STDERR);
}
waitpid($_, 0) for @pids;
That's because '>' doesn't like to share files. 那是因为'>'不喜欢共享文件。 Give each stage of the pipeline its own error log, and then execute something like this after the pipeline finishes:
为管道的每个阶段提供自己的错误日志,然后在管道完成后执行类似的操作:
system("cat error1.log erorr2.log error3.log > error.log");
Here's a platform independent way to aggregate the logs: 这是一种独立于平台的聚合日志的方法:
my @error_logs = qw( error1.log error2.log error3.log );
open my $errlog, ">>", "error.log" || die "probelm opening error log: $!";
foreach my $sublog ( @error_logs ) {
open my $fh, "<", $sublog || die "oh boy: $sublog: $!";
print "$sublog:"
print $errlog while $fh;
close $fh;
}
close $errlog;
But there also exist IO::Cat and File::Cat if you decide to lean that way. 但是如果你决定以这种方式倾斜,那么也存在IO :: Cat和File :: Cat 。
1)Corrected the name of the selfish meany that will not share files. 1)更正了不共享文件的自私公文的名称。
2) added log file collection 2)添加日志文件集合
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.