简体   繁体   English

从命令中捕获STDERR并在窗口下的perl中管道STDOUT

[英]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 :: CatFile :: 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.

相关问题 Perl:在 Windows 上的不同 colors 中显示 STDOUT 和 STDERR - Perl: Display STDOUT and STDERR in different colors on Windows 在Windows上重定向stdout / stderr - Redirecting stdout/stderr on Windows 如何在 Windows 中访问除 stdout、stderr 和 stdin 之外的继承匿名管道 HANDLE? - How to access an inherited anonymous pipe HANDLE, other than stdout, stderr & stdin, in Windows? 捕获外部程序的STDOUT和STDERR *同时*它正在执行(Ruby) - Capturing STDOUT and STDERR of an external program *while* it's executing (Ruby) 无法在Windows中重定向可执行文件的stdout或stderr - Failing to redirect stdout or stderr of an executable in windows Apache Tomcat Windows stdout/stderr 配置 - Apache Tomcat Windows stdout/stderr configuration 如何在 Windows 上的 CreateProcess() 中不继承标准输入、标准输出和标准错误 - How to NOT inherit stdin, stdout and stderr in CreateProcess() on Windows Windows python stdout和stderr到两个不同的文件 - windows python stdout and stderr to two different files 最快的命令,它接受管道,但在StdOut和StdErr上不生成文本 - fastest command, which accepts pipe, but generates no text on StdOut & StdErr 如何将进程的stdout和stderr传递到同一Handle? - How do I pipe the stdout and stderr of a process to the same Handle?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM