it-swarm.com.de

Ist es sicher, stdout und stderr ohne Dateideskriptorkopien in dieselbe Datei umzuleiten?

Ich beginne in einem leeren Verzeichnis.

$ touch aFile
$ ls
aFile

Dann habe ich ls zwei Argumente, von denen eines nicht in diesem Verzeichnis ist. Ich leite beide Ausgabestreams in eine Datei mit dem Namen output um. Ich benutze >> um nicht gleichzeitig zu schreiben.

$ ls aFile not_exist >>output 2>>output
$ cat output
ls: cannot access 'not_exist': No such file or directory
aFile

Welches scheint zu funktionieren. Gibt es Gefahren für diesen Ansatz?

27
exit_status

Nein, es ist nicht so sicher wie der Standard >>bar 2>&1.

Wenn du schreibst

foo >>bar 2>>bar

sie öffnen die Datei bar zweimal mit O_APPEND und erstellen zwei völlig unabhängige Dateiobjekte [1] mit jeweils eigenem Status (Zeiger, Öffnungsmodi usw.).

Dies unterscheidet sich stark von 2>&1, Bei dem nur der Systemaufruf dup(2) aufgerufen wird und die Aliase stderr und stdout für dasselbe Dateiobjekt austauschbar sind.

Nun gibt es ein Problem damit:

O_APPEND Kann zu beschädigten Dateien in NFS-Dateisystemen führen, wenn mehr als ein Prozess Daten gleichzeitig an eine Datei anfügt. Dies liegt daran, dass NFS das Anhängen an eine Datei nicht unterstützt, sodass der Client-Kernel diese simulieren muss, was ohne eine Race-Bedingung nicht möglich ist.

Normalerweise können Sie sich darauf verlassen, dass die Wahrscheinlichkeit, dass die Datei wie bar in foo >>bar 2>&1 Gleichzeitig von zwei verschiedenen Stellen aus geschrieben wird, sehr gering ist. Aber durch Ihren >>bar 2>>bar Haben Sie ihn ohne Grund nur um ein Dutzend Größenordnungen erhöht.

[1] "Open File Descriptions" im POSIX-Jargon.

22
mosvy

Was passiert, wenn Sie es tun?

some_command >>file 2>>file

ist, dass file zum zweimaligen Anhängen geöffnet wird. Dies ist auf einem POSIX-Dateisystem sicher möglich. Jeder Schreibvorgang für die Datei beim Öffnen zum Anhängen erfolgt am Ende der Datei, unabhängig davon, ob die Daten über den Standardausgabestream oder den Standardfehlerstrom übertragen werden.

Dies beruht auf der Unterstützung von Schreibvorgängen für atomare Anhänge im zugrunde liegenden Dateisystem. Einige Dateisysteme, wie z. B. NFS, unterstützen das atomare Anhängen nicht. Siehe z. die Frage "Ist das Anhängen von Dateien unter UNIX atomar?" auf StackOverflow.

Verwenden von

some_command >>file 2>&1

würde aber auch auf NFS funktionieren.

Jedoch mit

some_command >file 2>file

ist nicht sicher, da die Shell die Ausgabedatei (zweimal) abschneidet und jedes Schreiben in einem der Streams die bereits von der anderen geschriebenen Daten überschreibt Strom.

Beispiel:

$ { echo hello; echo abc >&2; } >file 2>file
$ cat file
abc
o

Die Zeichenfolge hello wird zuerst geschrieben (mit einer abschließenden neuen Zeile), und dann wird die Zeichenfolge abc gefolgt von einer neuen Zeile aus einem Standardfehler geschrieben, wobei die Zeichenfolge hell überschrieben wird. Das Ergebnis ist die Zeichenfolge abc mit einer neuen Zeile, gefolgt von den Überresten der ersten Ausgabe von echo, einer o und einer neuen Zeile.

Durch Vertauschen der beiden echo um die Wunde wird nur hello in der Ausgabedatei erzeugt, da diese Zeichenfolge zuletzt geschrieben wurde und länger als die Zeichenfolge abc ist. Die Reihenfolge, in der die Umleitungen erfolgen, spielt keine Rolle.

Es wäre besser und sicherer, die Redewendung zu verwenden

some_command >file 2>&1
22
Kusalananda

Es kommt darauf an, was Sie erreichen wollen. Es liegt an Ihnen zu entscheiden, ob es in Ordnung ist, Fehler in derselben Datei wie die Ausgabe zu haben. Hiermit wird lediglich Text in einer Datei mit der Funktionalität der Shell gespeichert, mit der Sie nach Belieben umleiten können. Es gibt kein absolutes Ja oder Nein. Da alles in Linux auf verschiedene Arten möglich ist, ist dies mein Weg ls notExistingFile existingFile >> output 2>&1 Um die Frage zu beantworten: In Bezug auf die Umleitung selbst ist es absolut sicher.

0
Angel