BEARBEITEN

BEARBEITEN

BEARBEITEN

Bitte sehen Sie sich nicht nur die akzeptierte Antwort an, sondern auch die anderen.

Frage

Warum funktioniert die Umleitung von STDOUT und STDERR zur gleichen Datei nicht, obwohl es so aussieht wie 1>[DATEINAME] 2>&1?

Hier ist ein Beispiel:

perl -e 'print "1\n" ; warn "2\n";' 1>a.txt 2>a.txt
cat a.txt
# outputs '1' only.

Nun, warum? Ich dachte, das funktioniert, weil ... STDOUT zu a.txt umgeleitet wird, ebenso wie STDERR. Was ist mit STDERR passiert?

Antwort1

Beide Umleitungen kürzen die Datei, so dass die zweite (in chronologischer Reihenfolge der Ausführung) die erste überschreibt. Versuchen Sie

rm a.txt ; touch a.txt ; perl -e 'print "1\n" ; warn "2\n";' 1>>a.txt 2>>a.txt

Oder verwenden Sie einfach den gleichen Dateideskriptor

perl -e 'print "1\n" ; warn "2\n";' 1>a.txt 2>&1

Antwort2

Mit 1>a.txt 2>&1ist Dateideskriptor Nr. 1dupliziertzu Nr. 2. Sie verweisen beide auf dieselbe „geöffnete Datei“ und haben beide die gleiche aktuelle Position und den gleichen Schreib-/Lesemodus. (Tatsächlich gibt es überhaupt keinen Unterschied zwischen der Verwendung von 2>&1 und 2<&1.)

Mit 1>a.txt 2>a.txtwerden beide Dateideskriptorenunabhängig voneinander geöffnetund haben separate Cursorpositionen. (Die Datei wird außerdem zweimal abgeschnitten.) Wenn Sie „Hallo“ in fd #1 schreiben, wird seine Position auf Byte 5 vorgerückt, aber fd #2 bleibt bei Byte 0. Beim Drucken in fd #2 werden die Daten einfach beginnend bei 0 überschrieben.

Dies lässt sich leicht erkennen, wenn der zweite Schreibvorgang kürzer ist:

$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>a.txt

$ cat a.txt 
123defg

Beachten Sie, dass Perl über interne Pufferung verfügt. In diesem Beispiel ist daher ein explizites „flush()“ erforderlich, um sicherzustellen, dass die Daten von fd #1 vor den Daten von fd #2 geschrieben werden. Andernfalls würden die Streams beim Beenden in unvorhersehbarer Reihenfolge geleert.

Zum Vergleich: Wenn die Dateideskriptoren gemeinsam genutzt werden, folgen die Schreibvorgänge einfach aufeinander:

$ perl -e 'STDOUT->print("abcdefg\n"); STDOUT->flush; STDERR->print("123");' >a.txt 2>&1

$ cat a.txt 
abcdefg
123

verwandte Informationen