【问题标题】:Capturing the output of STDERR while piping STDOUT to a file在将 STDOUT 管道传输到文件时捕获 STDERR 的输出
【发布时间】:2012-02-26 07:35:08
【问题描述】:

我的情况很奇怪。我正在尝试使用 Perl 自动备份一组 SVN 存储库。我正在使用 svnadmin dump 命令,该命令将转储发送到 STDOUT,并将遇到的任何错误发送到 STDERR。

我需要运行的命令格式如下:

svnadmin dump $repo -q >$backupFile

STDOUT 将转到备份文件,但是,我需要在我的 Perl 脚本中捕获 STDERR。

处理这种情况的正确方法是什么?

编辑: 澄清: STDOUT 将包含 SVN 转储数据 STDERR 将包含任何可能发生的错误

STDOUT 需要以文件结尾,而 STDERR 需要以 Perl 结尾。除了 STDOUT 的原始内容之外,任何时候都不能在该流中结束,否则转储将被损坏,我将得到比没有备份更糟糕的东西,一个糟糕的!

【问题讨论】:

    标签: perl


    【解决方案1】:

    好吧,在 perl 中也有通用的方法,但是 bash 解决方案(上面让我认为你正在寻找)是将 stderr first 重定向到 stdout 然后重定向标准输出到文件。直觉上,在您看到 bash 内部发生的事情之前,这并没有多大意义。但这有效:

    svnadmin dump $repo -q 2>&1 >$backupFile
    

    但是,不要以其他方式执行(即,将 2>&1 放在末尾),否则 stdout 和 stderr 的所有输出都将转到您的文件。 p>

    编辑以避免某些人认为这不起作用:

    你想要的是这个:

    # perl -e 'print STDERR "foo\n"; print "bar\n";' 2>&1 > /tmp/f 
    foo
    # cat /tmp/f
    bar
    

    特别是你不想要这个:

    # perl -e 'print STDERR "foo\n"; print "bar\n";' > /tmp/f 2>&1
    # cat /tmp/f
    foo
    bar
    

    【讨论】:

    • 天哪,不!错误数据无法进入文件 - 这就像将随机垃圾扔到 MySQL 转储中,这将是一场灾难!
    • 如果你按照我上面引用的方式进行操作,它不会进入文件。
    • 看着我看到 STDERR 被发送到 STDOUT - 我想我错过了一个非常重要的微妙之处?
    • @BartB:这样想:fd2 = fd1; fd1 = /tmp/f; 看看这样读更明智吗?完全没有问题。如果它们让您感到困惑,您应该始终阅读这样的 fd 重定向。
    【解决方案2】:

    这是一种方法:

    {
        local $/;   # allow reading stderr as a single chunk
    
        open(CMD, "svnadmin dump $repo -q 2>\&1 1>$backupFile |") or die "...";
        $errinfo = <CMD>;    # read the stderr from the above command
        close(CMD);
    }
    

    换句话说,使用shell 2>&1 机制将stderr 获取到Perl 可以轻松读取它的位置,并使用1> 获取发送到文件的转储。我写的关于 $/ 并将 stderr 作为单个块读取的内容只是为了方便 - 当然,您可以以任何您喜欢的方式读取 stderr。

    【讨论】:

    • 根据该建议,这可行吗?我的 $error = system("svnadmin dump $repo -q 2>\&1 1>$backupFile");
    • 按照您的建议使用 system() 会起作用,但 stderr 会进入脚本的标准输出,而不是像我的示例中那样被捕获。
    • 你为什么要这么辛苦?
    • tchrist:因为你还没有用更简单的方法打我们的脸 :-) 但是说真的,我一直假设 open() 或 die 模式会发现错误反引号不会。听起来我错了——你能确认一下吗?
    【解决方案3】:

    虽然 tchrist 肯定是正确的,您可以使用句柄方向和反引号来完成这项工作,但我也可以推荐 David Golden 的 Capture::Tiny 模块。它为捕获或发送 STDOUT 和 STDERR 提供了通用接口,您可以从那里随心所欲地使用它们。

    【讨论】:

      【解决方案4】:

      这东西真的很简单。看在上帝的份上,这就是发明反引号的目的。做吧:

      $his_error_output = `somecmd 2>&1 1>somefile`;
      

      瞧,你就完成了!

      我不明白问题出在哪里。小时候你的 gazzintas 不是像 Jethro 那样被钻进你的身体吗? :)

      【讨论】:

        【解决方案5】:

        来自perldoc perlopqx

        要分别读取命令的 STDOUT 和 STDERR,它是 最容易将它们分别重定向到文件,然后从那些文件中读取 程序完成后的文件:

        1. system("program args 1>program.stdout 2>program.stderr");

        【讨论】:

          猜你喜欢
          • 2018-10-03
          • 2019-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-04-13
          • 1970-01-01
          • 1970-01-01
          • 2011-04-25
          相关资源
          最近更新 更多