Warum unterscheidet sich das Verhalten von Befehl 1> Datei.txt 2> Datei.txt von Befehl 1> Datei.txt 2> & 1?

20

Wenn Sie sowohl stdout als auch stderr in dieselbe Datei umleiten möchten, können Sie dies mit command 1>file.txt 2>&1, oder tun command &>file.txt. Aber warum unterscheidet sich das Verhalten command 1>file.txt 2>file.txtvon den beiden oben genannten Befehlen?

Das Folgende ist ein Verifizierungsbefehl.

$ cat redirect.sh
#!/bin/bash

{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file.txt 2>&1
{ echo -e "output\noutput" && echo -e "error" 1>&2; } 1>file1.txt 2>file1.txt
{ echo -e "error" 1>&2 && echo -e "output\noutput"; } 1>file2.txt 2>file2.txt
{ echo -e "output" && echo -e "error\nerror" 1>&2; } 1>file3.txt 2>file3.txt
{ echo -e "error\nerror" 1>&2 && echo -e "output"; } 1>file4.txt 2>file4.txt

$ ./redirect.sh

$ echo "---file.txt---"; cat file.txt;\
echo "---file1.txt---"; cat file1.txt; \
echo "---file2.txt---"; cat file2.txt; \
echo "---file3.txt---"; cat file3.txt; \
echo "---file4.txt----"; cat file4.txt;
 ---file.txt---
output
output
error
---file1.txt---
error

output
---file2.txt---
output
output
---file3.txt---
error
error
---file4.txt----
output
rror

Soweit die Ergebnisse ersichtlich sind, scheint die zweite Echozeichenfolge die erste Echozeichenfolge zu überschreiben, wenn Sie ausgeführt werden command 1>file.txt 2>file.txt, aber ich weiß nicht, warum dies der Fall ist. (Gibt es irgendwo einen Hinweis?)

fhiyo
quelle

Antworten:

43

Sie müssen zwei Dinge wissen:

  • Ein offener Dateideskriptor, der auf der Seite des Anwendungsmodus eines Prozesses bekannt ist, verweist auf ein internes Kernelobjekt, das als Dateibeschreibung bezeichnet wird und eine Instanz einer offenen Datei ist. Es können mehrere Dateibeschreibungen pro Datei und mehrere Dateideskriptoren vorhanden sein, die eine Dateibeschreibung gemeinsam verwenden.
  • Die aktuelle Dateiposition ist ein Attribut einer Dateibeschreibung . Wenn also mehrere Dateideskriptoren einer einzelnen Dateibeschreibung zugeordnet sind, haben sie alle dieselbe aktuelle Dateiposition, und eine Änderung der mit einem solchen Dateideskriptor festgelegten Dateiposition wirkt sich auf alle anderen derartigen Dateideskriptoren aus.

    Solche Änderungen werden durch Prozesse Aufruf der in Kraft gesetzte read()/ readv(), write()/ writev(), lseek(), und ähnliche Systemaufrufe. Der echoBefehl ruft write()/ writev()natürlich auf.

Was also passiert, ist folgendes:

  • command 1>file.txt 2>&1Erstellt nur eine Dateibeschreibung, da die Shell eine Datei nur einmal öffnet. Durch die Shell werden sowohl die Standardausgabe- als auch die Standardfehlerdateideskriptoren dieser einzelnen Dateibeschreibung zugeordnet. Die Standardausgabe wird auf den Standardfehler dupliziert . Ein Schreibvorgang über einen der beiden Dateideskriptoren verschiebt die gemeinsam genutzte aktuelle Dateiposition: Bei jedem Schreibvorgang wird nach dem vorherigen Schreibvorgang die allgemeine Dateibeschreibung eingefügt. Und wie Sie sehen, echoüberschreiben sich die Ergebnisse der Befehle nicht gegenseitig.
  • command 1>file.txt 2>file.txtErstellt zwei Dateibeschreibungen, da die Shell dieselbe Datei als Antwort auf die beiden expliziten Umleitungen zweimal öffnet. Die Deskriptoren für Standardausgabe- und Standardfehlerdateien werden zwei verschiedenen Dateibeschreibungen zugeordnet, die dann wiederum derselben einzelnen Datei zugeordnet werden. Die beiden Dateibeschreibungen haben völlig unabhängige aktuelle Dateipositionen, und jeder Schreibvorgang wird sofort mit dem vorherigen Schreibvorgang für dieselbe Dateibeschreibung fortgesetzt. Und wie Sie sehen, kann das, was über das eine geschrieben wird, das, was über das andere geschrieben wird, auf verschiedene Arten überschreiben, je nachdem in welcher Reihenfolge Sie die Schreibvorgänge ausführen.

Weitere Lektüre

JdeBP
quelle
1
Sollte eher eine offene Dateibeschreibung als eine Dateibeschreibung sein . Es geht mehr um die Aufzeichnung, wie die Datei geöffnet wurde, als um die Datei selbst. Das ist zumindest die Terminologie, die in der POSIX-, Linux-, Solaris- und GNU-Dokumentation verwendet wird.
Stéphane Chazelas
16

Mit >wird die Datei überschrieben. Da stdout und stderr in zwei verschiedenen Vorgängen in die Datei schreiben, überschreibt der letzte zu schreibende Vorgang den ersten.

Du kannst tun:

command 1>>file.txt 2>>file.txt

oder

command &>file.txt Nur bash v4 und höher.

>> weist es an, die Datei anzuhängen, damit die Ausgabe der vorherigen Operationen nicht ersetzt wird.

&> ist nur eine einfachere Art zu schreiben 2>&1

Jesse_b
quelle
2
Warum wird die Ausgabe von ls angezeigt ls 1>&0und ls 0>&0immer noch?
Yvain
Ich bin überrascht, dass es >>funktioniert. Warum hat dies nicht das Problem zweier Dateibeschreibungen mit unabhängigen Offsets? @JdeBP, weißt du? Ich dachte, dass das Öffnen einer Datei im Anhänge-Modus gleichbedeutend mit dem Öffnen im Schreib-Modus ist, bei dem nach der endgültigen Position gesucht und dann das weitere Suchen untersagt wird.
JoL
4
@jlmg: Dateien im Append-Modus können gesucht werden, aber jedem Schreibvorgang wird eine implizite Suche bis zum Ende vorangestellt. Ob diese implizite Suche atomar ist, ist mir weniger klar.
Kevin
1
Das hängt ganz von der Folgefrage ab. Solche, die damit verwandt sind, zeigen an, dass die Antwort unvollständig ist. Und es ist unwahrscheinlich, dass die Leute die folgenden Fragen nachschlagen, ohne auch die vollständige Antwort wissen zu wollen. Daher ist es sehr wahrscheinlich, dass solche Follow-on-Fragen Antworten haben, die Informationen duplizieren und daher als Duplikate geschlossen werden.
trlkly
1
@ Kevin, auf vollständig POSIX-kompatiblen Dateisystemen ist die implizite O_APPEND-Suche atomar. Das heißt, nicht jedes Dateisystem implementiert die relevante Semantik ordnungsgemäß - z. B. hat NFS (mindestens Version 3 und früher - mir ist nicht klar, ob Version 4) nicht die relevante Unterstützung im Wire-Protokoll integriert, so dass der Server über diese verfügt Keine Möglichkeit zu wissen, ob ein Client eine Datei mit geöffnet hat O_APPEND.
Charles Duffy