Warum wird beim Umleiten der Ausgabe einer Datei an sich selbst eine leere Datei erstellt?
In Bash, warum?
less foo.txt > foo.txt
und
fold foo.txt > foo.txt
ein leeres produzieren foo.txt
? Da durch einen Anhang wie beispielsweise less eggs.py >> eggs.py
zwei Kopien des Texts erstellt werden eggs.py
, kann davon ausgegangen werden, dass durch ein Überschreiben eine Kopie des Texts erstellt wird.
Beachten Sie, ich sage nicht, dass dies ein Fehler ist, es ist eher ein Hinweis auf etwas Tiefes über Unix.
bash
unix
unix-utils
Seewalker
quelle
quelle
Antworten:
Bei Verwendung von
>
wird die Datei im Kürzungsmodus geöffnet, sodass der Inhalt entfernt wird, bevor der Befehl versucht, sie zu lesen.Wenn Sie verwenden
>>
, wird die Datei im Anhänge-Modus geöffnet, damit die vorhandenen Daten erhalten bleiben. Es ist jedoch immer noch sehr riskant, in diesem Fall dieselbe Datei als Eingabe- und Ausgabedatei zu verwenden. Wenn die Datei groß genug ist, um nicht in die Größe des Lese-Eingabepuffers zu passen, kann sie unbegrenzt größer werden, bis das Dateisystem voll ist (oder Ihr Datenträgerkontingent erreicht ist).Wenn Sie eine Datei sowohl als Eingabe als auch als Ausgabe mit einem Befehl verwenden möchten, der keine direkte Änderung unterstützt, können Sie einige Problemumgehungen verwenden:
Verwenden Sie eine Zwischendatei und überschreiben Sie die Originaldatei, wenn Sie fertig sind und wenn beim Ausführen des Dienstprogramms kein Fehler aufgetreten ist (dies ist die sicherste und gebräuchlichste Methode).
Vermeiden Sie die Zwischenablage auf Kosten eines möglichen teilweisen oder vollständigen Datenverlusts, falls ein Fehler oder eine Unterbrechung auftritt. In diesem Beispiel wird der Inhalt von
foo.txt
als Eingabe an eine Subshell (in Klammern) übergeben, bevor die Datei gelöscht wird. Der vorherige Inode bleibt am Leben, da die Subshell ihn geöffnet hält, während Daten gelesen werden. Die Datei, die vom inneren Dienstprogramm (hierfold
) mit demselben Namen geschrieben wurde (foo.txt
) verweist auf einen anderen Inode, da der alte Verzeichniseintrag technisch so entfernt wurde, dass es während des Vorgangs zwei verschiedene "Dateien" mit demselben Namen gibt. Wenn die Subshell endet, wird der alte Inode freigegeben und seine Daten gehen verloren. Achten Sie darauf, dass Sie genügend Speicherplatz haben, um die alte und die neue Datei gleichzeitig zwischenzuspeichern. Andernfalls gehen Daten verloren.quelle
sponge
von moreutils kann auch helfen.fold foo.txt | sponge foo.txt
- oderfold foo.txt | sponge !$
sollte auch tun.Die Datei wird von der Shell zum Schreiben geöffnet, bevor die Anwendung sie lesen kann. Das Öffnen der Datei zum Schreiben schneidet sie ab.
quelle
In der Bash
... > foo.txt
leert sich der Stream-Umleitungsoperator,foo.txt
bevor der linke Operand ausgewertet wird .Man könnte die Befehlsersetzung verwenden und das Ergebnis als Workaround ausdrucken. Diese Lösung benötigt weniger zusätzliche Zeichen als in anderen Antworten:
Achtung: Dieser Befehl behält keine Zeilenumbrüche bei
foo.txt
. Weitere Informationen finden Sie im Kommentarbereich untenHier wird die Subshell vor dem Stream-Redirection-Operator
$(...)
ausgewertet , wodurch die Informationen erhalten bleiben .>
quelle
tmp=$(cmd; printf q); printf '%s' "${tmp%q}"
. Sie haben jedoch ein anderes Problem mit dieser Antwort verpasst: Es heißt "Subshell", wenn es "Befehlsersetzung" bedeutet. Ja, Befehlsersetzungen sind im Allgemeinen Subshells, aber nicht umgekehrt, und Subshells sind im Allgemeinen keine Hilfe für dieses Problem.