Unterschied zwischen cat und '>', um eine Datei auf Null zu setzen

23

Unterscheiden sich diese beiden Befehle in Bezug auf das Löschen von Dateien? Ist Letzteres eine kürzere Art, Ersteres zu tun? Was passiert hinter den Kulissen?

Beide

$ cat /dev/null > file.txt

$ > file.txt 

Ausbeute

-rw-r--r--  1 user  wheel  0 May 18 10:33 file.txt
KM.
quelle

Antworten:

28

cat /dev/null > file.txtist eine nutzlose Verwendung von Katze .

Im Grunde führt das cat /dev/nulleinfach dazu, dass catnichts ausgegeben wird. Ja, es funktioniert, aber es wird von vielen missbilligt, weil es dazu führt, dass ein externer Prozess aufgerufen wird, der nicht erforderlich ist.
Es ist eines dieser Dinge, die einfach deshalb gemeinsam sind, weil sie gemeinsam sind.

Die Verwendung von just > file.txtfunktioniert bei den meisten Shells, ist jedoch nicht vollständig portierbar. Wenn Sie vollständig portabel sein möchten, bieten sich folgende Alternativen an:

true > file.txt
: > file.txt

Beide :und truegeben keine Daten aus und sind Shell-Builtins (wohingegen cates sich um ein externes Dienstprogramm handelt), daher sind sie leichter und "richtiger".

 

Aktualisieren:

Wie tylerl in seinem Kommentar erwähnt hat, gibt es auch die >| file.txtSyntax.

Die meisten Shells haben eine Einstellung, die verhindert, dass sie eine vorhandene Datei über abschneiden >. Sie müssen >|stattdessen verwenden. Dies soll menschliches Versagen verhindern, wenn Sie wirklich anhängen wollten >>. Sie können das Verhalten mit einschalten set -C.

Daher denke ich, dass die einfachste, geeignetste und portabelste Methode zum Abschneiden einer Datei ist:

:>| file.txt
Patrick
quelle
2
Der Doppelpunktbefehl ist in POSIX definiert . Es handelt sich um eine Nulloperation zum Erweitern von Befehlszeilenargumenten.
Kojiro
3
LOL, "Katzenmissbrauch"
KM.
2
@kojiro muss :auch von POSIX eingebaut werden und unterscheidet sich tatsächlich darin, truedass es als "spezielles" eingebaut gilt .
Jw013
2
Vergiss nicht Noclobber . >| fileist eine explizite abgeschnitten.
TylerL
1
Nein muss truenicht eingebaut werden und war es traditionell nicht. :ist in allen Schalen der Familie Bourne verbaut. :ist ein spezielles Feature für POSIX ( : > filewird also die Shell verlassen, wenn filesie nicht zum Schreiben in POSIX-Shells geöffnet werden kann) und truenicht. POSIX erwähnt sogar, dass dies :möglicherweise effizienter ist als trueauf einigen Systemen.
Stéphane Chazelas
23

In Bezug auf die Portabilität:

                      Bourne POSIX  zsh    csh/tcsh  rc/es  fish
> file                Y      Y      N(1)   N(1)      N      N
: > file              N/Y(2) Y(3)   Y      Y(4)      N(5)   N(5)
true > file           Y(5)   Y      Y      Y(5)      Y(5)   Y(5)
cat /dev/null > file  Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
eval > file           Y(3,8) Y(3)   Y      Y(6)      Y      Y
cp /dev/null file (7) Y(5)   Y      Y(5)   Y(5)      Y(5)   Y(5)
printf '' > file      Y(5)   Y      Y      Y(5)      Y(5)   Y

Anmerkungen:

  1. Mit Ausnahme von In shoder kshEmulation wird für Umleitungen ohne Befehl in zsh ein Standardbefehl angenommen ( catandernfalls ein Pager für die Standardumleitung ), der mit den Variablen NULLCMD und READNULLCMD optimiert werden kann. Das ist inspiriert von der ähnlichen Funktion in(t)csh
  2. :In UnixV7 wurden Umleitungen zunächst nicht durchgeführt, da dies :auf halbem Weg zwischen einem Kommentar-Leader und einem Null-Befehl interpretiert wurde. Später waren sie und wie für alle Builtins, wenn die Umleitung fehlschlägt, verlässt das die Shell.
  3. :evalWenn die Umleitung fehlschlägt und spezielle integrierte Funktionen verwendet werden, wird die Shell beendet ( bashnur im POSIX-Modus).
  4. Interessanterweise (t)cshdefiniert dies ein Null-Label (für goto), sodass goto ''dort eine Verzweigung stattfinden würde. Wenn die Umleitung fehlschlägt, wird die Shell beendet.
  5. Es sei denn , / wenn der entsprechende Befehl in verfügbar ist $PATH( im :Allgemeinen ist das nicht, true, cat, cpund im printfAllgemeinen ist (POSIX verlangt , dass sie)).
  6. Wenn die Umleitung fehlschlägt, wird die Shell beendet.
  7. Wenn filees sich jedoch um einen Symlink zu einer nicht vorhandenen Datei handelt, cplehnen einige Implementierungen wie GNUs die Erstellung ab.
  8. In den ersten Versionen der Bourne-Shell wurde das Umleiten von Buildins jedoch nicht unterstützt

In Bezug auf die Lesbarkeit:

(Dieser Abschnitt ist sehr subjektiv)

  • > file. Das >sieht zu sehr nach einer Eingabeaufforderung oder einem Kommentar aus. Auch die Frage, die ich beim Lesen stellen werde (und die meisten Shells beschweren sich über dasselbe), lautet: Welche Ausgabe leiten Sie genau um? .
  • : > file. :wird als No-Op-Befehl bezeichnet. Das liest sich also gleich so, als würde eine leere Datei erzeugt. Auch hier :kann dies jedoch leicht übersehen und / oder als Aufforderung angesehen werden.
  • true > file: Was hat Boolescher Wert mit Umleitung oder Dateiinhalt zu tun? Was ist hier gemeint? fällt mir als erstes ein, wenn ich das lese.
  • cat /dev/null > file. Verketten /dev/nullin file? catOft wird es als Befehl gesehen, den Inhalt der Datei zu sichern, was immer noch Sinn macht: Sich den Inhalt der leeren Datei sichernfile , ein bisschen wie eine verschlungene Art zu sagen, cp /dev/null fileaber dennoch verständlich.
  • cp /dev/null file. Kopiert den Inhalt der leeren Datei nach file. Sinnvoll, auch wenn jemand, der nicht weiß, wie er cpstandardmäßig vorgehen soll, denkt, dass Sie versuchen, auch fileein nullGerät herzustellen .
  • eval > fileoder eval '' > file. Führt nichts aus und leitet die Ausgabe an a um file. Für mich ergibt das Sinn. Seltsam, dass es keine alltägliche Redewendung ist.
  • printf '' > file: druckt explizit nichts in eine Datei. Derjenige, der mir am meisten Sinn macht.

In Bezug auf die Leistung

Der Unterschied wird sein, ob wir eine eingebaute Shell verwenden oder nicht. Wenn nicht, muss ein Prozess gegabelt, der Befehl geladen und ausgeführt werden.

evalwird garantiert in allen Schalen gebaut. :ist überall dort eingebaut, wo es verfügbar ist (Bourne / csh likes). trueist nur in Bourne-ähnlichen Shells eingebaut.

printfist in modernste Bourne-artige Muscheln eingebaut und fish.

cpund sind in der catRegel nicht eingebaut.

cp /dev/null fileRuft jetzt keine Shell-Umleitungen auf, also Dinge wie:

find . -exec cp /dev/null {} \;

effizienter sein als:

find . -exec sh -c '> "$1"' sh {} \;

(wenn auch nicht unbedingt als:

find . -exec sh -c 'for f do : > "$f"; done' sh {} +

).

Persönlich

Persönlich verwende ich : > filein Bourne-ähnlichen Muscheln und verwende heutzutage nichts anderes als Bourne-ähnliche Muscheln.

Stéphane Chazelas
quelle
Was ist dd of=file count=0?
Kojiro
2
@kojiro, wird bei einigen Implementierungen von dd(wie mindestens Solaris 10) count=0ignoriert. dd if=/dev/null of=filewäre tragbarer. In jedem Fall ist das unabhängig von der Shell.
Stéphane Chazelas
OK, aber es ist nicht weniger einbeziehungswürdig als cp /dev/null file, oder?
Kojiro
2
@kojiro, cp /dev/null fileist eine verbreitete Redewendung. Ich beschränke mich auf diese, es geht nicht darum, alle möglichen Wege aufzulisten.
Stéphane Chazelas
5

Vielleicht möchten Sie sich ansehen truncate, was genau das bewirkt: eine Datei abschneiden.

Beispielsweise:

truncate --size 0 file.txt

Dies ist wahrscheinlich langsamer als die Verwendung true > file.txt.

Mein Hauptpunkt ist jedoch: truncateIst zum Abschneiden von Dateien gedacht, während die Verwendung von> den Nebeneffekt hat, eine Datei abzuschneiden.

Fabian
quelle
2
Abschneiden ist nützlich, wenn Sie eine Datei auf etwas anderes als 0 abschneiden möchten. Das heißt, auch ohne Shell ist eine seltsame Aussage: Können Sie einen Kontext beschreiben truncate, in dem verfügbar wäre, aber weder C-Bibliotheken >noch unistdBibliotheken verfügbar wären?
Kojiro
Nicht wirklich. Es gibt wahrscheinlich eine elegantere Lösung für jedes Skript oder jede Programmiersprache.
Fabian
3
truncateist ein FreeBSD-Dienstprogramm, das vor relativ kurzer Zeit (2008) zu den GNU-Coreutils hinzugefügt wurde (obwohl der --sizeGNU-Long-Option-Stil GNU-spezifisch ist). Ich würde nicht sagen, dass es tragbar ist. cp /dev/null filewürde ohne eine Shell-Umleitung funktionieren und wäre portabler.
Stéphane Chazelas
Okay, ich werde diesen Kommentar zur Portabilität entfernen. Obwohl Ihre Definition der letzten scheint sich zu unterscheiden.
Fabian
2

Die Antwort hängt ein bisschen davon ab, was file.txtist und wie der Prozess darauf schreibt!

Ich werde einen allgemeinen Anwendungsfall anführen: Sie haben eine wachsende Protokolldatei mit dem Namen file.txtund möchten sie drehen.

Deshalb kopieren Sie zum Beispiel file.txtin file.txt.saveund kürzen dann ab file.txt.

In diesem Szenario IF die Datei nicht geöffnet wird another_process(zB: another_processkönnte ein Programm Ausgabe auf diese Datei, zum Beispiel ein Programm Protokollierung etwas), dann zwei Vorschläge sind gleichwertig und beide arbeiten gut (aber die zweite wird als die bevorzugte erste "cat / dev / null> file.txt" ist eine nutzlose Verwendung von Cat und öffnet und liest auch / dev / null).

Aber das eigentliche Problem wäre, wenn der other_processnoch aktiv ist und noch ein offenes Handle zur Datei.txt hat.

Je nachdem, wie other processdie Datei geöffnet wurde, treten zwei Hauptfälle auf :

  • Wenn other_processes auf die normale Weise geöffnet wird, zeigt das Handle weiterhin auf die frühere Position in der Datei, z. B. mit einem Versatz von 1200 Byte. Der nächste Schreibvorgang beginnt daher bei Offset 1200, und Sie haben wieder eine Datei mit 1200 Bytes (+ was auch immer other_process geschrieben hat), mit 1200 führenden Nullzeichen! Ich nehme an, nicht das, was du willst .

  • Wenn der Zeiger im "Anfügemodus" other_processgeöffnet file.txtwird, sucht er bei jedem Schreiben aktiv nach dem Ende der Datei. Wenn Sie es abschneiden, wird es daher bis Byte 0 "suchen", und Sie werden nicht die schlechten Nebenwirkungen haben! Das ist was du willst (... normalerweise!)

Beachten Sie, dass dies bedeutet, dass Sie beim Abschneiden einer Datei sicherstellen müssen, dass alle, die other_processnoch an diesen Speicherort schreiben, diese im Modus "Anhängen" geöffnet haben. Andernfalls müssen Sie diese stoppen other_processund erneut starten, damit sie auf den Anfang der Datei anstatt auf den vorherigen Speicherort zeigen.

Weitere Informationen finden Sie unter /programming//a/16720582/1841533. Unter /programming//a/984761/1841533 finden Sie ein kurzes Beispiel für den Unterschied zwischen der normalen Protokollierung und der Protokollierung im Anhängemodus

Olivier Dulac
quelle
2
Sehr wenig von dieser Antwort ist tatsächlich relevant für oder beantwortet die Frage. Der Unterschied zwischen a cat /dev/null > fileund a > fileist a cat /dev/nullund das macht keinen Unterschied für die Datei.
jw013
@ jw013: Stimmt! Aber ich wollte nur die Gelegenheit nutzen, um die Information "Was Sie wollen / Nicht was Sie wollen" erneut zu formulieren, da diese nicht sehr bekannt ist, und jemanden hart treffen könnte, der versucht, Protokolle zu drehen (ein häufiger Fall, bei dem Sie dies möchten) eine Datei abschneiden).
Olivier Dulac
1
Es gibt eine Zeit und einen Ort für alles. Ihre Informationen können in einem anderen Kontext nützlich sein, gehören aber nicht hierher. Sie sollten einen geeigneteren Ort dafür finden, da in dieser völlig unabhängigen Umleitungsfrage niemand nachsehen wird, der versucht, Protokolle zu drehen. Hier ist Ihre Antwort das Äquivalent eines digitalen Unkrauts, genau wie eine ansonsten nützliche Kürbispflanze in der Mitte eines Maisfeldes als Unkraut gelten würde.
JW013
1

Ich mag das und benutze es oft, weil es sauberer aussieht und nicht, dass jemand versehentlich die Eingabetaste gedrückt hat:

echo -n "" > file.txt

Sollte auch ein eingebaut sein?

awsm
quelle
3
Es gibt viele Möglichkeiten, eine Datei auf Null zu setzen. Ich denke KM. Ich war nur daran interessiert, den Unterschied zwischen den beiden in der Frage gezeigten Methoden zu verstehen.
drs
6
Viele echoImplementierungen werden nicht unterstützt -n(und würden -n<SPC><NL>hier ausgegeben . printf '' > file.txtWäre portabler (zumindest auf modernen / POSIX-Systemen).
Stéphane Chazelas