为什么 perl eval 上的输出在常见的 bash 输出和将 STDOUT + STDERR 重定向到文件之间有所不



我的代码是:

  perl -e'
  use strict; use warnings;
  my $a={};
  eval{ test(); };
  sub test{
     print "11n";
     if( $a->{aa} eq "aa"){
        print "aan";
     }
     else{
        print "bbn";
     }
  }'

终端上的输出为:

  11
  Use of uninitialized value in string eq at -e line 9.
  bb

如果我在文件中重定向,输出顺序会有所不同。为什么?

  perl -e'
  ...
  ' > t.log 2>&1

猫 T.log:

  Use of uninitialized value in string eq at -e line 9.
  11
  bb

我的 perl 版本:

  This is perl 5, version 18, subversion 4 (v5.18.4) built for x86_64-linux-thread-multi
  (with 20 registered patches, see perl -V for more detail)

问题的更简单演示:

$ perl -e'print("abcn"); warn("defn");'
abc
def
$ perl -e'print("abcn"); warn("defn");' 2>&1 | cat
def
abc

这是由于 STDOUT 和 STDERR 缓冲方式的差异。

  • STDERR 未缓冲。
  • 如果 STDOUT 连接到终端,则在遇到换行符时刷新其缓冲区。
  • 否则,STDOUT 会在缓冲区已满时刷新其缓冲区。

$| = 1;关闭了 STDOUT 的缓冲[1]。

$ perl -e'$| = 1; print("abcn"); warn("defn");' 2>&1 | cat
abc
def

  1. 实际上,当前select的 ed 句柄,如果未指定句柄,则print写入该句柄,默认情况下为 STDOUT。
这只是

一个自动刷新问题,没有评估问题。

解决方案是:

perl -e'
use strict; 
use warnings;
$|++; # <== this autoflush print output
my $a={};
test();
sub test{ 
   print "11n";
   if( $a->{aa} eq "aa"){
      print "aan";
   }
   else{
      print "bbn";
   }
}' > t.log 2>&1

在某些情况下,终端上是相同的问题:

perl -e'print("abc"); print(STDERR "def"); print("ghi");'

获得正确顺序的唯一保存方法是打开自动刷新!

@dgw+池上==>谢谢

最新更新