2013-03-14 19 views
6

我希望Perl只有在STDOUT不相同的情况下才能写入STDERR。例如,如果STDOUT和STDERR都将输出重定向到终端,那么我不想打印STDERR。仅当STDOUT是不同的目的地时,如何才能打印到STDERR?

考虑下面的例子(outerr.pl):

#!/usr/bin/perl 

use strict; 
use warnings; 

print STDOUT "Hello standard output!\n"; 
print STDERR "Hello standard error\n" if ($someMagicalFlag); 
exit 0 

现在考虑这个(这是我想达到的目标):

bash $ outerr.pl 
Hello standard output! 

但是,如果我从重定向到一个文件,我想获得:

bash $ outerr.pl > /dev/null 
Hello standard error 

和与之相似的另一种方式圆:

bash $ outerr.pl 2> /dev/null 
Hello standard output! 

如果我再直接既出/犯错到文件,然后只出应显示:

bash $ outerr.pl > foo.txt 2>&1 
bash $ cat foo.txt 
Hello standard output! 

那么,有没有一种方法来评估/确定是否OUT和ERR和指向相同的“事物”(描述符?)?

+0

'STDERR'和'STDOUT'有它们自己的描述符,即1和2。它们通常也都打印到控制台。 – squiguy 2013-03-14 18:32:13

+2

我怀疑你应该做的是退后一步,重新考虑你想要这个的原因。几乎可以肯定有更好的方法来实现你的真实目标,不管它是什么。 – 2013-03-14 18:59:35

+0

我和Ilmari Karonen在一起。我真的不明白为什么你会担心这一点。它不应该用于复制邮件。 STDOUT和STDERR本质上应该不同。标称消息转到STDOUT,错误或警告消息转到STDERR。也不应该绕圈...永远。 – titanofold 2013-03-14 19:06:45

回答

5

在Unix类系统,你应该能够做到:

my @stat_err = stat STDERR; 
my @stat_out = stat STDOUT; 

my $stderr_is_not_stdout = (($stat_err[0] != $stat_out[0]) || 
          ($stat_err[1] != $stat_out[1])); 

但是,这不会在Windows上,它没有真正的inode编号工作。它给出了误报(认为它们不同时不同)和假阴性(认为它们在没有时是相同的)。

+0

这当然是我会做的。 – tchrist 2013-03-14 21:00:13

+0

+1指出它不便携,并且仍然有用。 – 2013-03-14 22:59:18

+0

谢谢@cjm。这是*完全*我在找什么。 ...什么是Windows,顺便说一句? ;-) – 2013-03-15 05:07:22

4

你可以做到这一点(几乎)与-t:

-t STDERR 

将是真实的,如果它是一个终端,同样的标准输出。

这仍然不会告诉你什么终端,如果你重定向到同一个文件,你仍然可以得到两个。

因此,如果

-t STDERR && ! (-t STDOUT) || -t STDOUT && !(-t STDERR) 

或更短

-t STDOUT^-t STDERR # thanks to @mob 

你知道你没事。

编辑:为案件的解决方案,既STDERR和stdout常规文件:

汤姆孙玮建议统计和比较dev和伊诺领域。这将在UNIX中起作用,但正如@cjm指出的那样,而不是在Windows中。

如果你能保证没有其他程序会写入文件,你可以做以下的在Windows和UNIX:

  1. 检查位置STDOUT和STDERR的文件描述符的,如果 他们不相等,您将其中一个>>重定向到一个 非空文件。
  2. 否则,向文件描述符2写入42个字节
  3. 寻找文件描述符1的结尾。如果它比以前增加了42个,那么很可能两个都重定向到同一个文件。如果不变,则文件不同。如果它改变了,但不是42,那么别人正在那里写,所有的投注都关闭(但是,你不在Windows中,所以统计方法将起作用)。
+0

问题是关于检测'STDOUT'和'STDERR'是否相同(文件,终端或其他)的问题。 – 2013-03-14 18:48:54

+0

@JimStewart你觉得我说*几乎*?并警告说,在重定向到同一个文件的情况下它不起作用?但是,如果不分析lsof的输出,就可以得到最好的结果。 – Ingo 2013-03-14 18:52:31

+1

'(-t STDOUT)^(-t STDERR)'至少会告诉你是否只有一个数据流进入终端。这是一个非常好的开始。 – mob 2013-03-14 18:54:30

相关问题