Echo zum Dateideskriptor überschreibt die Datei?

7

Ich habe Probleme zu verstehen, was passiert, wenn ich versuche, in einen Dateideskriptor zu schreiben. Es scheint den ursprünglichen Inhalt zu überschreiben? Ist das erwartetes Verhalten?

Ich habe dies im folgenden Beispiel wiederholt:

$ echo "The quick brown fox ..." > example.txt  
$ echo "The quick brown fox ..." >> example.txt
$ cat example.txt
The quick brown fox ...  
The quick brown fox ...
$ exec 88<>example.txt
$ cat example.txt
The quick brown fox ...  
The quick brown fox ...
$ echo "jumped" >&88  
$ cat example.txt
jumped  
ck brown fox ...  
The quick brown fox ...
$ echo "jumped" >&88  
$ cat example.txt
jumped  
jumped  
n fox ...  
The quick brown fox ...
Zoonose
quelle

Antworten:

11

Da Sie den Deskriptor 88 nicht gelesen hatten, war die aktuelle Suchposition "0", und daher fand das Schreiben zu diesem Zeitpunkt statt.

Wenn Sie stattdessen die Datei zuvor gelesen haben, werden Anhänge ausgeführt:

bash-4.2$ cat <&88
The quick brown fox ...
The quick brown fox ...

bash-4.2$ echo hello >&88

bash-4.2$ cat example.txt 
The quick brown fox ...
The quick brown fox ...
hello

bash-4.2$ echo more >&88

bash-4.2$ cat example.txt 
The quick brown fox ...
The quick brown fox ...
hello
more
Stephen Harris
quelle
Beeindruckend! Dies bedeutet also, dass der Dateideskriptor (in diesem Beispiel 88) eine separate Suchposition zur Standardkatze beibehält? dh Katze example.txt
Zoonose
Danke Stephen. Habe das gerade ausprobiert und du hast recht. Interessanterweise bleibt das Problem bestehen, wenn ich weiterhin die Datei wiederhole und dann den Deskriptor wiederhole (ohne den Deskriptor zu lesen). Wenn also andere Prozesse in die Datei schreiben, muss ich den Deskriptor ständig einlesen, bevor ich ihn schreibe!
Zoonose
4
@Zoonose: Wenn Sie ausführen cat example.txt, öffnet cat die Datei, erhält einen Deskriptor mit einer Suchposition , die am Anfang der Datei beginnt, liest sie bis zum Ende und schließt dann den Deskriptor. Wenn Sie ausführen exec 88<>example.txt, öffnet bash die Datei und erhält einen Deskriptor mit einer Suchposition, die am Anfang der Datei beginnt. Die Datei selbst behält keine Suchposition bei, stattdessen wird für jeden geöffneten Dateideskriptor eine Position beibehalten.
P Daddy
4
Selbst wenn Sie cat <&88zuerst schreiben, handelt es sich bei den folgenden Schreibvorgängen nur um reguläre Schreibvorgänge an der Stelle, an der das Schreiben gestoppt wurde, und nicht um ordnungsgemäße Anhänge. Sie könnten in der Zwischenzeit Daten überschreiben, die von einem anderen Prozess geschrieben wurden. Wenn das Anhängen gewünscht wird, ist der >>Umleitungsoperator der (einzige) Weg. Soweit ich weiß, hat Bash nicht wirklich die Möglichkeit, Dateien zu suchen, und es erlaubt auch nicht, gleichzeitig im Lese- / Schreibmodus und im Anhänge-Modus zu öffnen .
Ilkkachu
4

Wie @Zoonose richtig hervorhebt, hat jeder Dateideskriptor seine eigene Lese- / Schreib-Cursorposition in der Datei, mit der er verbunden ist. Und eine Datei kann entweder von der Shell geöffnet werden, wenn Sie eine Umleitung wie verwenden <>, oder von einem Programm wie cat.

Die Zahlen, die Sie als "Filedescriptor" betrachten, sind jedoch nur Verweise auf die tatsächlichen Filedescriptors im Kernel, und es ist völlig normal, dass ein Filedescriptor mehrere solcher Referenznummern hat, entweder innerhalb eines einzelnen Prozesses oder zwischen Prozessen.

Wenn Sie also ein Terminalfenster öffnen (oder sich mit ssh anmelden), beginnen Sie mit einem einzelnen Dateiskriptor, der für Ihr Terminal geöffnet ist und in Ihrem Shell-Prozess als fd # 0, fd # 1 und fd # 2 verbunden ist. Jeder Prozess, mit dem die Shell beginnt, erbt diese standardmäßig - außer wenn Sie Pipes oder Umleitungen verwendet haben.

Die Umleitung >>kennzeichnet den Dateiskriptor als O_APPEND, sodass beim Schreiben durch diesen Dateiskriptor der Cursor ignoriert wird und zum Ende der Datei gewechselt wird.

Durch die Umleitung >wird die Zieldatei nur einmal abgeschnitten, bevor geschrieben wird. Daher wird jedes Schreiben danach normalerweise in den leeren Bereich nach dem Ende der Datei verschoben.

Writes in einer Datei tun nicht selbst Ursache Abschneiden; Sie ersetzen einfach alles, was sich an der aktuellen Position befindet, und strecken bei Bedarf das Dateiende.

Beachten Sie, somecmd >&88dass das stdout (fd # 1) für somecmd den Dateiskriptor mit fd # 88 der aktuellen Shell teilt. Das heißt, es wird die O_APPENDOption teilen , falls vorhanden. Es wird nicht dazu führen, dass es erneut abgeschnitten wird. Das ist eine einmalige Sache.

Was Sie in diesem Fall sehen, ist, dass es bei der Verwendung keine Kürzung gibt >&88, da fd # 88 nicht mit geöffnet >>wurde und daher Schreibvorgänge aus mehreren Prozessen verschachtelt werden können.

Martin
quelle