stdout到file1,stderr到file2,都正确交错到stdout和文件

时间:2011-08-12 01:22:44

标签: bash redirect stdout stderr tee

鉴于第三方计划,如何同时进行:

  1. 将stdout写入z.stdout
  2. 将stderr写入z.stderr
  3. 正确传递退出代码
  4. 以正确的交错顺序写入stdout
  5. 这是我一直在使用的测试程序(delayed_interleaved_stdout_stderr.pl):

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    # fixme: debug, uncomment to force stdout flushing
    # use English '-no_match_vars';
    # $OUTPUT_AUTOFLUSH = 1;
    
    # use sleeps to simulate delays and test buffering
    use Time::HiRes 'sleep';
    
    foreach my $num ( 0..9 ) {
      if ( 0 == $num % 2 ) {
        print STDOUT $num, ":stdout\n";
      }
      else {
        print STDERR $num, ":stderr\n";
      }
      sleep 0.25;
    }
    

    到目前为止,我已经能够做到1,2,3了:

    ( set -o pipefail; \
      ( set -o pipefail; delayed_interleaved_stdout_stderr.pl \
        | tee z.stdout; exit $? \
      ) 3>&1 1>&2 2>&3 | tee z.stderr; exit $? \
    ) 3>&1 1>&2 2>&3
    

    感谢related answer lhunath和朋友,我将其简化为:

    delayed_interleaved_stdout_stderr.pl > >(tee z.stdout) 2> >(tee z.stderr >&2)
    

    但是,我无法获得正确的交错顺序。 stderr立即打印,并且(推测缓冲的)stdout最后都打印出来。

    1:stderr
    3:stderr
    5:stderr
    7:stderr
    9:stderr
    0:stdout
    2:stdout
    4:stdout
    6:stdout
    8:stdout
    

    运行delayed_interleaved_stdout_stderr.pl本身会以正确的0-9顺序显示。强制stdout正确刷新工作(请参阅注释的fixme部分),但我将无法修改真实文件。

    也许我错过了一些基本的东西,我开始怀疑这是否可能:(

2 个答案:

答案 0 :(得分:2)

要求4是棘手的。 stdout和stderr的缓冲逻辑隐藏在libc中,为了改变它,你需要欺骗应用程序认为它写入终端。

expect包附带的

unbuffer将为您完成此操作。警告:即使写入终端,stdout也是行缓冲的,所以如果你的应用程序没有写完整行,那么这将无法正常工作。

答案 1 :(得分:1)

我确认我可以对第三方程序执行stdout冲洗。鉴于此,我将继续

delayed_interleaved_stdout_stderr.pl > >(tee z.stdout) 2> >(tee z.stderr >&2)

感谢您的帮助!