2013-03-14 7 views
6

Ich möchte, dass Perl nur dann an STDERR schreibt, wenn STDOUT nicht dasselbe ist. Wenn beispielsweise STDOUT und STDERR die Ausgabe an das Terminal umleiten, möchte ich nicht, dass STDERR gedruckt wird.Wie drucke ich nur dann auf STDERR, wenn STDOUT ein anderes Ziel ist?

Betrachten Sie das folgende Beispiel (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 

Nun ist diese betrachten (das ist, was ich erreichen möchte):

bash $ outerr.pl 
Hello standard output! 

Wenn ich jedoch auf eine Umleitung aus Datei, würde ich bekommen:

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

und Similary andersrum:

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

Wenn ich-direct wieder beide aus/err auf die gleiche Datei, dann sollte nur aus angezeigt werden:

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

So ist es eine Möglichkeit, zu bewerten/zu bestimmen, ob OUT und ERR und auf dasselbe "Ding" zeigen (Deskriptor?)?

+0

'STDERR' und' STDOUT' haben ihre eigenen Deskriptoren, nämlich 1 und 2. Sie drucken beide im Allgemeinen auch auf die Konsole. – squiguy

+2

Ich vermute, dass was Sie wirklich tun sollten, ist einen Schritt zurück und überdenken Sie die Gründe, warum Sie dies wollen. Es gibt fast sicher einen besseren Weg, um Ihr wahres Ziel zu erreichen, was auch immer es sein mag. –

+0

Ich bin mit Ilmari Karonen. Ich kann nicht wirklich sehen, warum du dir darüber Gedanken machen würdest. Es sollte nicht zum Duplizieren von Nachrichten sein. STDOUT und STDERR sollten von Natur aus anders sein. Nominale Nachrichten werden an STDOUT gesendet und Fehler- oder Warnmeldungen werden an STDERR gesendet. Weder sollte über Runden ... jemals. – titanofold

Antwort

5

Auf Unix-Systemen sollten Sie in der Lage zu tun: auf Windows

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])); 

Aber das wird nicht funktionieren, die Zahlen nicht wirklich Inode hat. Es gibt sowohl falsche Positive (denkt, dass sie anders sind, wenn sie es nicht sind) als auch falsche Negative (denkt, dass sie dieselben sind, wenn sie es nicht sind).

+0

Das würde ich sicherlich tun. – tchrist

+0

+1 für Hinweis darauf, es ist nicht tragbar, und immer noch nützlich zu wissen. –

+0

Danke @cjm. Das ist * GENAU * was ich suche. ... Was ist Windows, übrigens? ;-) –

4

können Sie tun, dass (fast) mit -t:

-t STDERR 

wahr ist, wenn es sich um ein Terminal ist, und ebenfalls für STDOUT.

Dies würde immer noch nicht sagen, welches Terminal, und wenn Sie auf die gleiche Datei umleiten, können Sie beide erhalten.

Wenn also

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

oder kürzer

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

Sie wissen, dass Sie in Ordnung.

EDIT: Lösungen für den Fall, dass beide STDERR und STDOUT sind normale Dateien:

Tom Christianson vorgeschlagen, die Entwickler und ino Felder stat und zu vergleichen. Dies funktioniert in UNIX, aber, wie @cjm darauf hinwies, nicht in Windows.

Wenn Sie garantieren können, dass kein anderes Programm in die Datei schreiben, könnten Sie die folgenden Aktionen in Windows und UNIX:

  1. Überprüfen Sie die Position der Datei-Deskriptoren für STDOUT und STDERR an sind, wenn Sie sind nicht gleich, Sie haben einen von ihnen mit >> in eine nichtleere Datei umgeleitet.
  2. Andernfalls schreiben Sie 42 Bytes in Dateideskriptor 2
  3. Suchen Sie nach dem Ende des Dateideskriptors 1. Wenn es 42 mehr als zuvor ist, sind die Chancen hoch, dass beide auf die gleiche Datei umgeleitet werden. Wenn es unverändert ist, sind die Dateien unterschiedlich. Wenn es geändert wird, aber nicht durch 42, schreibt jemand anderes dort, alle Wetten sind aus (aber dann, Sie sind nicht in Windows, so wird die Stat-Methode funktionieren).
+0

Die Frage ist speziell zu erkennen, wenn 'STDOUT' und' STDERR' gleich sind (Datei, Terminal oder sonstwie). –

+0

@JimStewart WARUM denkst du, dass ich * fast * gesagt habe? Und gewarnt, dass es im Falle der Umleitung auf die gleiche Datei nicht funktioniert? Aber es ist das Beste, was Sie bekommen können, ohne etwas wie die Ausgabe von lsof zu analysieren. – Ingo

+1

'(-t STDOUT)^(-t STDERR)' wird Ihnen zumindest sagen, ob nur ein Stream zu einem Terminal geht. Das ist ein ziemlich guter Anfang. – mob