2013-03-14 18 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

相關問題