【问题标题】:How to redirect STDOUT and STDERR to a variable如何将 STDOUT 和 STDERR 重定向到变量
【发布时间】:2011-05-23 20:44:03
【问题描述】:

我想将STDERRSTDOUT 重定向到一个变量。我这样做了。

close(STDOUT);
close(STDERR);

my $out;
open(STDOUT, ">>", \$out);
open(STDERR, ">>", \$out);

for(1..10)
{
    print "print\n"; # this is ok. 
    warn "warn\n"; # same
    system("make"); # this is lost. neither in screen nor in variable.
}

system 的问题。我也希望捕获此调用的输出。

【问题讨论】:

    标签: perl system stdout stderr redirect


    【解决方案1】:

    使用Capture::Tiny

    【讨论】:

      【解决方案2】:

      您是否要在变量中捕获输出?如果是这样,您可以使用带有适当重定向的反引号或qx{}。例如,您可以使用:

      #/usr/bin/env perl
      use strict;
      use warnings;
      
      # Ensure we have a way to write messages
      open my $fh, '>', "output" or die;
      
      close(STDOUT);
      close(STDERR);
      
      my $out;
      open(STDOUT, ">>", \$out) or do { print $fh, "failed to open STDOUT ($!)\n"; die };
      open(STDERR, ">>", \$out) or do { print $fh, "failed to open STDERR ($!)\n"; die };
      
      foreach my $i (1..10)
      {
          print "print $i\n"; 
          warn "warn $i\n";
          my $extra = qx{make pth$i 2>&1};
          print $fh "<<$i>><<$out>><<$extra>>\n";
      }
      

      (我碰巧在目录中有程序 pth1、pth2 和 pth3 - 它们都正常;pth4 及更高版本将错误写入 stderr;重定向是必要的。)

      你应该经常检查open()等操作是否成功。

      为什么这是必要的?因为写入变量需要进行写入的进程的合作 - 而make 不知道如何合作。

      【讨论】:

        【解决方案3】:

        redirect and restore STDOUT 有多种方式。其中一些也与 STDERR 一起工作。这是我最喜欢的两个:

        使用select

        my $out;
        open my $fh, ">>", \$out;
        select $fh;
        print "written to the variable\n";
        select STDOUT;
        print "written to original STDOUT\n";
        

        使用local

        my $out
        do {
            local *STDOUT;
            open STDOUT, ">>", \$out;
            print "written to the variable\n";
        };
        print "written to original STDOUT\n";
        

        享受吧。

        【讨论】:

          【解决方案4】:

          发生这种情况的原因是 STDOUT 和 STDERR“文件句柄”等同于 shell 提供给 perl 二进制文件的 stderr 和 stdout 句柄。为了达到你想要的,你应该使用open而不是system

          【讨论】:

          • @Israfil:这是的方法。
          【解决方案5】:

          为什么不use IPC::Open3

          【讨论】:

          • 这不适用于当前进程,只适用于新打开的进程。
          【解决方案6】:

          TLDR 答案

          use Capture::Tiny;

          合并 STDOUT 和 STDERR

          如果您想合并STDOUT(来自print()s)和STDERR(来自warn()s),请使用...

          my ($merged,  @result) = capture_merged { print "Hello, world!" };  # static code
          my ($merged,  @result) = capture_merged { eval $codetoeval };       # code in variable
          

          分离的 STDOUT 和 STDERR

          如果你想让它们分开......

          my ($stdout, $stderr, @result) = capture { print "Hello, world!" };   # static code
          my ($stdout, $stderr, @result) = capture { eval $codetoeval };        # code in variable
          

          评估结果

          @result表示成功,成功为[1],失败为[]。 Tiny 有很多其他功能,您可以查看其他情况,例如代码引用等。但我认为上面的代码应该满足任何 Perl 开发人员的大部分需求。

          【讨论】:

            猜你喜欢
            • 2014-07-22
            • 1970-01-01
            • 2012-08-07
            • 2021-08-19
            • 1970-01-01
            • 1970-01-01
            • 2022-01-18
            • 2011-11-23
            • 2011-03-02
            相关资源
            最近更新 更多