Entspricht die Umleitung mit ">>" ">", wenn die Zieldatei noch nicht vorhanden ist?


80

Betrachten Sie eine Shell wie Bash oder sh. Der grundlegende Unterschied zwischen >und >>zeigt sich in einem Fall, in dem die Zieldatei vorhanden ist:

  • > schneidet die Datei auf die Größe Null ab und schreibt dann;
  • >> schneidet nicht ab, sondern schreibt (hängt an das Ende der Datei an).

Wenn die Datei nicht vorhanden ist, wird sie mit der Größe Null erstellt. dann geschrieben an. Dies gilt für beide Betreiber. Möglicherweise sind die Operatoren gleichwertig, wenn die Zieldatei noch nicht vorhanden ist.

Sind sie wirklich

Antworten:


107

tl; dr

Nein >>ist im Wesentlichen "immer nach dem Ende der Datei suchen", während >ein Zeiger auf die zuletzt geschriebene Stelle beibehalten wird.


Volle Antwort

(Hinweis: Alle meine Tests wurden unter Debian GNU / Linux 9 durchgeführt.)

Noch ein Unterschied

Nein, sie sind nicht gleichwertig. Es gibt noch einen anderen Unterschied. Es kann sich unabhängig davon manifestieren, ob die Zieldatei zuvor vorhanden war oder nicht.

Führen Sie dazu einen Prozess aus, der Daten generiert und mit >oder >>(z pv -L 10k /dev/urandom > blob. B. ) in eine Datei umleitet . Lass es laufen und ändere die Größe der Datei (zB mit truncate). Sie werden sehen, dass >das (wachsende) Offset erhalten >>bleibt, während es immer an das Ende angehängt wird.

  • Wenn Sie die Datei auf eine kleinere Größe kürzen (die Größe kann Null sein)
    • >ist egal, es wird am gewünschten Offset geschrieben, als ob nichts passiert wäre; unmittelbar nachdem das Abschneiden des Offsets über das Ende der Datei hinausgeht, wird die Datei ihre alte Größe wiedererlangen und weiter wachsen. Fehlende Daten werden mit Nullen gefüllt (möglichst sparsam).
    • >> wird an das neue Ende angehängt, wächst die Datei von ihrer abgeschnittenen Größe.
  • Wenn Sie die Datei vergrößern
    • >ist egal, es wird am gewünschten Offset geschrieben, als ob nichts passiert wäre; Unmittelbar nach dem Ändern der Größe befindet sich der Versatz irgendwo in der Datei. Dies führt dazu, dass die Datei für eine Weile nicht mehr wächst, bis der Versatz das neue Ende erreicht. Dann wächst die Datei normal.
    • >> wird an das neue Ende angehängt, wird die Datei von ihrer vergrößerten Größe vergrößert.

Ein weiteres Beispiel ist das Anhängen (mit einem separaten >>) einer zusätzlichen Angabe, wenn der Datenerzeugungsprozess ausgeführt wird und in die Datei geschrieben wird. Dies ähnelt dem Vergrößern der Datei.

  • Der Erzeugungsprozess mit >schreibt an seinem gewünschten Versatz und überschreibt schließlich die zusätzlichen Daten.
  • Der Erzeugungsprozess mit >>überspringt die neuen Daten und fügt sie an (möglicherweise tritt eine Race-Bedingung auf, die beiden Streams verschachteln sich möglicherweise, es sollten jedoch keine Daten überschrieben werden).

Beispiel

Ist es in der Praxis wichtig? Es gibt diese Frage :

Ich führe einen Prozess aus, der viel Ausgabe auf stdout produziert. Alles in eine Datei senden [...] Kann ich eine Art Protokollrotationsprogramm verwenden?

Diese Antwort besagt, dass die Lösung logrotatemit der folgenden copytruncateOption vorliegt:

Kürzen Sie die ursprüngliche Protokolldatei, nachdem Sie eine Kopie erstellt haben, anstatt die alte Protokolldatei zu verschieben und optional eine neue zu erstellen.

Nach dem, was ich oben geschrieben habe, >wird das abgeschnittene Protokoll durch Umleiten mit in kürzester Zeit groß. Sparsamkeit spart den Tag, es sollte kein nennenswerter Speicherplatz verschwendet werden. Trotzdem enthält jedes aufeinanderfolgende Protokoll immer mehr führende Nullen, die völlig unnötig sind.

Wenn Sie jedoch logrotateKopien erstellen, ohne die Sparsamkeit zu wahren, benötigen diese führenden Nullen mit jeder Kopie mehr Speicherplatz. Ich habe das Verhalten des Tools noch nicht untersucht. Es ist möglicherweise intelligent genug, wenn die Komprimierung spontan oder spärlich erfolgt (sofern die Komprimierung aktiviert ist). Dennoch können die Nullen nur Ärger verursachen oder bestenfalls neutral sein; nichts Gutes in ihnen.

In diesem Fall ist using >>statt >deutlich besser, auch wenn die Zieldatei gerade erstellt wird.


Performance

Wie wir sehen können, verhalten sich die beiden Operatoren nicht nur zu Beginn, sondern auch später unterschiedlich. Dies kann zu (geringfügigen?) Leistungsunterschieden führen. Im Moment habe ich keine aussagekräftigen Testergebnisse, die dies bestätigen oder widerlegen könnten, aber ich denke, Sie sollten nicht automatisch davon ausgehen, dass ihre Leistung im Allgemeinen gleich ist.


9
So >>wird im Wesentlichen "immer nach dem Ende der Datei suchen", während >ein Zeiger auf die zuletzt geschriebene Stelle beibehalten wird. Es sieht so aus, als
ob es

10
>>Verwendet auf der Ebene des Systemaufrufs das O_APPENDFlag toopen() . Und tatsächlich >verwendet O_TRUNC, während >>nicht. Die Kombination von O_TRUNC | O_APPENDwäre auch möglich, die Shell-Sprache bietet diese Funktion einfach nicht.
Ilkkachu

3
@jjmontes, die Standardquelle wäre POSIX: pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/… aber natürlich enthält das Handbuch von Bash auch Beschreibungen der Umleitungsoperatoren, einschließlich der von ihm unterstützten Nicht-Standardoperatoren: gnu.org/ software / bash / manual / html_node / Redirections.html
ilkkachu

2
@ilkkachu Ich fand das interessant, da es Details zu O_APPEND erklärt, über die ich mich nach Ihrem Kommentar gewundert habe
jjmontes

1
@Mokubai, Jedes vernünftige Betriebssystem hätte die Dateilänge zur Hand, wenn es geöffnet ist, und das Aktivieren eines Flags und das Verschieben des Versatzes zum Ende sollten in allen anderen Buchhaltungsfunktionen einfach verschwinden. Der Versuch, O_APPENDmit einem lseek()vor jedem zu emulieren, write()wäre jedoch unterschiedlich, da dies den zusätzlichen Systemaufruf-Overhead bedeuten würde. (Und natürlich würde es nicht funktionieren, da ein anderer Prozess write()dazwischen liegen könnte.)
ilkkachu
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.