Öffnet Bash Dateien in O_APPEND, wenn ">>" unter Linux verwendet wird?

38

Wenn wir verwenden, echo 1234 >> some-filebesagt die Dokumentation, dass die Ausgabe angehängt wird.

Ich vermute, wenn eine Datei nicht existiert, erstellt O_CREAT eine neue Datei. Wenn >verwendet, schneidet O_TRUNC die vorhandene Datei ab.

Im Fall von >>: Wird die Datei als O_WRONLY (oder O_RDWR) geöffnet und versucht, den Vorgang zu beenden, und der Schreibvorgang wird ausgeführt, wobei O_APPEND simuliert wird? Oder wird die Datei als O_APPEND geöffnet und dem Kernel überlassen, um sicherzustellen, dass das Anhängen erfolgt?

Ich frage dies, weil ein Conserver-Prozess einige durch Echo eingefügte Markierungen überschreibt, wenn die Ausgabedatei vom NFS-Einhängepunkt stammt. Die NFS-Dokumentation besagt, dass O_APPEND auf dem Server nicht unterstützt wird, sodass der Client-Kernel damit umgehen muss. Ich schätze, der Conserver-Prozess verwendet O_APPEND, ist sich jedoch nicht sicher, ob er >>unter Linux läuft, und stellt daher hier die Frage.

Prem
quelle
12
Das Problem bei NFS ist nicht, dass O_APPENDes nicht unterstützt wird. Das Problem ist, dass es emuliert ist. In einem lokalen Dateisystem O_APPEND überschreiben mehrere Prozesse, die in dieselbe Datei schreiben, die mit geöffnet wurde , niemals die Daten des anderen. Auf NFS O_APPENDwird emuliert, indem bis zum Ende vor dem Schreiben gesucht wird, was die Möglichkeit von Rennbedingungen lässt. Daran führt bei NFS kein Weg vorbei. Jeder Parallelschreiber muss eine eigene Datei schreiben. Die einzige Möglichkeit, dies zu umgehen, besteht darin, einen Serverprozess auf dem NFS-Server einzurichten, die Protokollierer zu protokollieren |nc server portund eingehende Daten an das Protokoll anzuhängen.
Guntram Blohm unterstützt Monica
@GuntramBlohm, +1, danke für die Bestätigung. Grundsätzlich empfehlen wir, nur einen Writer-Prozess für die Datei zu verwenden, und alle anderen Writer-Prozesse durchlaufen diesen Prozess.
Prem
So viele gute Antworten. Ich bin mir nicht sicher, welche Antwort ich annehmen soll. Zuerst zeigte Bruce Ediger, dass O_APPEND verwendet wird. Als nächstes zeigte Random832, dass dies in den Standards angegeben ist. Schließlich zeigte Eric Renouf den Quellcode mit der gleichen Antwort. Alle drei Perspektiven ergänzen das endgültige Gesamtbild.
Prem
6
Kurz gesagt, NFS ist eine Menge Fehler und sollte nicht verwendet werden.
R ..
2
Ja, aber das haben wir schon gelernt, als O_EXCL erfunden wurde.
Kevin

Antworten:

60

Ich habe folgendes ausgeführt: strace -o spork.out bash -c "echo 1234 >> some-file"um deine Frage herauszufinden. Folgendes habe ich gefunden:

open("some-file", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

In dem Verzeichnis, in dem ich den echoBefehl ausgeführt habe, war keine Datei mit dem Namen "some-file" vorhanden .

Bruce Ediger
quelle
50

Dies geschieht nicht nur in Bash, sondern wird vom Standard verlangt.

Aus der Single Unix Spezifikation :

Die Umleitung der angehängten Ausgabe bewirkt, dass die Datei, deren Name sich aus der Erweiterung des Wortes ergibt, zur Ausgabe im angegebenen Dateideskriptor geöffnet wird. Die Datei wird so geöffnet, als ob die Funktion open () , wie sie im Volume System Interfaces von POSIX.1-2008 definiert ist, mit dem Flag O_APPEND aufgerufen wurde. Ist die Datei nicht vorhanden, wird sie erstellt.

Daher muss es jede POSIX-kompatible Shell tun. Auf einigen Unix-Systemen /bin/shkann es sich um eine Nicht-POSIX-Bourne-Shell handeln (die Bourne-Shell wurde ursprünglich geschrieben, bevor sie O_APPENDerfunden wurde), und die verfügbare POSIX-Shell ist in der Regel eine solche ksh, die shan einem anderen Pfad wie der von Solaris verfügbar ist /usr/xpg4/bin.

Random832
quelle
2
Interessanterweise ist eine Shell, die dies nicht tut, die Bourne-Shell. Die Bourne-Shell wird ohne O_TRUNC und lseek () s bis zum Ende geöffnet. Das wäre, weil es geschrieben wurde, bevor das O_APPEND-Flag hinzugefügt wurde open(). >>selbst wurde von seinem Vorgänger die Thomson-Shell vorgestellt.
Stéphane Chazelas
1
@ StéphaneChazelas Außerdem habe ich die C-Shell-Quelle nach verschiedenen Versionen durchsucht, und das O_APPEND-Flag wurde erst mit 4.3BSD-Reno eingeführt.
Random832
Es sagt "als ob", also könnte es nicht anders implementiert werden (aber den gleichen beobachtbaren Effekt erzeugen)? Es sieht nicht so aus, als ob der Standard die Verwendung von O_APPEND erfordert , nur etwas, das sich "als ob" verhält.
Thomas
1
@Thomas Das bedeutet, dass Sie das gesamte Verhalten von O_APPEND dokumentieren und am Ende jedes Schreibvorgangs neu positionieren müssen. Das "Als ob" ist nur eine Standardausgabe, die es ermöglichen soll, zB auf andere Weise als durch Aufrufen der Funktion open () auf nicht-traditionellen Unix-Plattformen geöffnet zu werden.
Random832
+1, um zu zeigen, dass dieses Verhalten in den Standards enthalten ist.
Prem
32

In der Quelle wird O_APPEND verwendet. Für die Bash 4.3.30 in make_cmd.cZeile 710-713 lesen Sie:

case r_appending_to:                /* >>foo */
case r_append_err_and_out:          /* &>> filename */
  temp->flags = O_APPEND | O_WRONLY | O_CREAT;
  break;
Eric Renouf
quelle
+1, um die Antwort aus der Perspektive des Quellcodes anzuzeigen.
Prem
19

Untersuchen wir das unter Verwendung straceeines lokalen (nicht NFS) Dateisystems:

$ strace -eopen -- bash -c "echo foo >> /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_APPEND, 0666) = 3

$ strace -eopen -- bash -c "echo foo > /tmp/testfile000" 2>&1 | grep /tmp/testfile000
open("/tmp/testfile000", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3

Andere Muscheln, nämlich dash, dash, shvon Busybox‘und mkshverhalten sich die gleiche Weise.

Die Option -e openbedeutet -e trace=open, nur den open()Systemaufruf zu verfolgen .

Franklin Piat
quelle