Wie funktioniert "cat <> file"?

42

cat < filedruckt den Inhalt der Datei nach stdout.

cat > fileliest stdin, bis Ctrl+ Derkannt wird und der Eingabetext in die Datei geschrieben wird .

cat <> fileDruckt, zumindest in meiner Version von Bash, den Inhalt der Datei zufriedenstellend (ohne Fehler), ändert jedoch weder die Datei noch den Änderungszeitstempel.

Wie rechtfertigt der Bash-Standard das scheinbar Ignorierte >in der dritten Aussage - und was noch wichtiger ist, tut er etwas?

Qix
quelle

Antworten:

47

Bash verwendet <>, um einen Lese- / Schreib-Dateideskriptor zu erstellen :

Der Umleitungsoperator

[n]<>word

Bewirkt, dass die Datei, deren Name die Erweiterung des Wortes ist, zum Lesen und Schreiben im Dateideskriptor n oder im Dateideskriptor 0 geöffnet wird, wenn n nicht angegeben ist. Wenn die Datei nicht existiert, wird sie erstellt.

cat <> fileÖffnet fileLese- / Schreibzugriff und bindet ihn an Deskriptor 0 (Standardeingabe). Es entspricht im Wesentlichen < filejedem vernünftig geschriebenen Programm, da normalerweise niemand versucht, auf die Standardeingabe zu schreiben, aber wenn dies möglich wäre.

Sie können ein einfaches C - Programm schreiben , dass aus direkt zu testen - write(0, "hello", 6)schreibt helloin fileüber Standardeingabe.

<>sollte mit dem gleichen Effekt auch in jeder anderen POSIX-kompatiblen Shell funktionieren .

Michael Homer
quelle
1
Schreiben ... an stdin? ... Gibt es einen gültigen Anwendungsfall dafür?
Qix
3
Aus der Hand fällt mir kein guter ein. Es 4<>fileist nützlich, einen expliziten Deskriptor ( ) anzugeben, und ich nehme an, 0 ist ein ebenso guter Standard wie jeder andere, wenn Sie ihn weglassen. Lesen von stdout ist nicht besser.
Michael Homer
5
<>Auf einigen Systemen (wie Linux) ist es auch nützlich, Named Pipes zu öffnen, ohne sie zu blockieren, bis ein anderer Prozess sie zum Schreiben öffnet.
Stéphane Chazelas
1
@Qix: Nun, Schreiben (0, "Passwort:", 10) ist eine gute Möglichkeit, ein Passwort einzugeben, wenn Sie eine Eingabeaufforderung für eine Art von tty vornehmen möchten. Ich bin es gewohnt, es nur auf stderr zu sehen, aber ohne besonderen Grund funktioniert die gleiche Technik nicht auf stdin.
Joshua
3
@Qix - aus dem POSIX- Grundprinzip - Der <>Operator kann nützlich sein, um eine Anwendung zu schreiben, die mit mehreren Terminals funktioniert und gelegentlich eine Shell starten möchte. Diese Shell wäre wiederum nicht in der Lage, Anwendungen auszuführen, die von einem normalen steuernden Terminal ausgeführt werden, es sei denn, sie könnte <>... wie ... den Pager verwenden more, der aus Standardfehlern liest, um seine Befehle abzurufen, also Standardeingabe und Standardausgabe sind beide für den üblichen Gebrauch verfügbar. cat food | more - >/dev/tty03 2<>/dev/tty03
mikeserv
38

<> fileöffnet die Datei (auf Dateideskriptor 0 (stdin) standardmäßig wie <) in Lese + Schreibmodus ohne Abschneiden und die Erstellung der Datei , wenn es nicht vorher noch nicht gab .

Das entspricht den O_RDWR|O_CREATFlags, die an den open()Systemaufruf übergeben werden. Im Gegensatz dazu <ist O_RDONLYund >ist O_WRONLY|O_CREAT|O_TRUNCund >> O_WRONLY|O_CREAT|O_APPEND.

Das Beschreiben von stdin ist nicht oft nützlich, da Anwendungen normalerweise nicht in ihre stdin schreiben. Anwendungen erwarten normalerweise nicht, dass sie in einem Dateideskriptor lesen und schreiben, den sie beim Start erhalten. Sie lesen normalerweise aus stdin (oder einem Dateideskriptor, den sie selbst öffnen) und schreiben in stdout oder stderr (oder einen Dateideskriptor, den sie selbst öffnen).

<> kann seinen Nutzen haben:

  • Möglicherweise bevorzugen cat <> fileSie es, cat < filewenn der Befehl nicht fehlschlagen soll, wenn er filenicht vorhanden ist file. Stattdessen wird ein leerer Befehl erstellt.
  • Der nicht abschneidende Aspekt von <>macht es nützlich, Dateien an Ort und Stelle zu überschreiben. In diesem Fall verwenden Sie es jedoch im Allgemeinen nicht für den Dateideskriptor 0:

    printf xxx 1<> file

    ersetzt die ersten 3 Bytes von filemit xxx.

  • Auf einigen Systemen wie Linux <>öffnet eine Named Pipe (FIFO) die Named Pipe ohne zu blockieren (ohne darauf zu warten, dass ein anderer Prozess das andere Ende öffnet) und stellt sicher, dass die Pipe-Struktur erhalten bleibt. Zum Beispiel in:

    mkfifo pipe; sed 's/foo/bar/g' <> pipe

    sedverarbeitet eingehende Daten von einer beliebigen Anzahl anderer Prozesse, die darauf schreiben, und sieht sie nie eof.

Stéphane Chazelas
quelle
1
Beachten Sie, dass in AT & T ksh93 <>standardmäßig 1<>(stdout) anstelle von 0<>(stdin) verwendet wird. Dies ist ein POSIX-Kompatibilitätsfehler, den ich gemeldet habe und der in der nächsten Version behoben wird. github.com/att/ast/issues/75 Aber bis aktuelle ksh93-Versionen nicht mehr verwendet werden, müssen Sie die Dateideskriptornummer <>angeben , um sie portabel zu verwenden .
Martijn Dekker
@MartijnDekker, ich weiß, ich war derjenige, der dir von Anfang an davon erzählt hat ;-). Beachten Sie, dass dies nur für ksh93t + (wo sich das Verhalten geändert hat) und höher gilt.
Stéphane Chazelas
Was sind (oder waren) die Systeme im Gegensatz zu Linux, wo mkfifo fifo; exec 3<>fifowürde blockieren?
Onkel Billy