Öffnen Umleitungsoperatoren Dateideskriptoren immer parallel?

7

1. Betrachten Sie Snippet Nr. 1:

$ cat test.txt > test.txt
cat: test.txt: input file is output file

Es scheint, dass catder Deskriptor der Eingabedatei auf test.txt verweist. Wenn er dann versucht, den Deskriptor der Ausgabedatei auf test.txt zu setzen, wird der obige Fehler ausgegeben. Hier scheint catder Redirect-Operator bekannt zu sein und versucht daher, den Ausgabedateideskriptor auf test.txt zu setzen

2. Betrachten Sie Snippet Nr. 2:

$ cat 1.txt
1:CAT
2:dog
$ sed 's/cat/CAT/g' test.txt
1:CAT
2:dog
$ sed 's/cat/CAT/g' test.txt > test.txt
$ cat test.txt # Note that test.txt is now empty
$

Hier sehen wir, dass sedtest.txt (letztes Argument) im Lesemodus geöffnet und gleichzeitig test.txtals Dateiausgabedeskriptor festgelegt wird. Außerdem '>'überschreibt der Bediener den Inhalt der Datei, BEVOR er sedmit dem Lesen beginnt.

Mir ist bekannt, dass Befehle in einer Pipeline parallel ausgeführt werden, aber keine Informationen über das Verhalten von Umleitungsoperatoren gefunden wurden. Alle unterstützenden Links wären hilfreich.

Kent Pawar
quelle

Antworten:

11

Zusätzlich zu den Unterlagen jordanm Punkte, möchte ich sicherstellen, eine falsche Vorstellung in Ihrer Frage das ausgeführte Programm dargestellt zu korrigieren ist nicht Umleitungen zu behandeln. Es ist ihnen kaum bewusst. Die Shell verarbeitet Weiterleitungen.

Ein Programm wird mit drei geöffneten Dateien gestartet: stdin (# 0), stdout (# 1) und stderr (# 2). Wenn Sie nur ein Programm über Ihre Shell-Eingabeaufforderung ausführen, werden diese mit Ihrem Endgerät verbunden, sodass das Programm liest, was Sie eingeben (stdin), und Ausgabe (stdout) und Fehler (stderr) auf Ihr Terminal druckt.

Als Beispiel laufe ich einfach catin einem Terminal (was ttyheißt /dev/pts/31). Ich kann überprüfen, mit welchen Dateien es geöffnet ist lsof:

$ lsof -a -p `pidof cat` -d0,1,2
COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
cat     21257 anthony    0u   CHR 136,31      0t0   34 /dev/pts/31
cat     21257 anthony    1u   CHR 136,31      0t0   34 /dev/pts/31
cat     21257 anthony    2u   CHR 136,31      0t0   34 /dev/pts/31

In der Tat können wir sehen, dass das Terminal für alle drei geöffnet ist. Versuchen wir stattdessen einen ziemlich albernen Katzenaufruf : cat < /dev/zero > /dev/null 2>/dev/full, der alle drei umleitet:

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
cat     21838 anthony    0r   CHR    1,5      0t0 1030 /dev/zero
cat     21838 anthony    1w   CHR    1,3      0t0 1028 /dev/null
cat     21838 anthony    2w   CHR    1,7      0t0 1031 /dev/full

Die Shell implementierte diese Umleitungen, indem sie die drei Geräte als stdin, stdout und stderr (anstelle des Terminals) übergab. Die Schale implementiert in ähnlicher Weise Rohre. Versuchen wir es cat | dd > /dev/null(eine ziemlich dumme Pfeife):

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
cat     22507 anthony    0u   CHR 136,31      0t0       34 /dev/pts/31
cat     22507 anthony    1w  FIFO    0,8      0t0 56081395 pipe
cat     22507 anthony    2u   CHR 136,31      0t0       34 /dev/pts/31

COMMAND   PID    USER   FD   TYPE DEVICE SIZE/OFF     NODE NAME
dd      22508 anthony    0r  FIFO    0,8      0t0 56081395 pipe
dd      22508 anthony    1u   CHR 136,31      0t0       34 /dev/null
dd      22508 anthony    2u   CHR 136,31      0t0       34 /dev/pts/31

Beachten Sie, wie die Shell ein Rohr geöffnet hat und es verwendet hat, um das stdout von catmit dem stdin von zu verbinden dd. Und weiter , wie es angeschlossen ddist stdout /dev/null.

Die ausgeführten Befehle kennen die Umleitungen nicht wirklich. Sie verwenden einfach stdin, stdout, stderr wie gewohnt. Dies können alle das Terminal sein oder sie können zu / von einer Datei, einem Gerät oder einer Pipe zu einem anderen Programm umgeleitet werden. Oder sogar einen Netzwerk-Socket, wenn Ihre Shell dies unterstützt.

Selbst die lächerlich kompliziertesten Pipelines sind nur Anweisungen an die Shell, wie diese drei Dateihandles verbunden werden, bevor das Programm ausgeführt wird.

(HINWEIS: Einige Programme verhalten sich anders, wenn eines davon an ein Terminal angeschlossen ist. Bei interaktiver Verwendung ist dies jedoch normalerweise benutzerfreundlicher. Wechselt beispielsweise lszur einspaltigen Ausgabe und zu keiner Farbe, wenn stdout nicht a ist Terminal - das ist normalerweise das, was Sie möchten, wenn Sie es an ein anderes Programm übergeben möchten. Einige Programme behandeln die Eingabeaufforderung anders, wenn stdin kein Terminal ist. Und so weiter.)

derobert
quelle
Danke @derobert! Das war eine großartige Erklärung. Ich habe mich umgesehen, ob es eine Möglichkeit gibt, zu überprüfen, wie cathinter den Kulissen funktioniert, und zum Glück haben Sie das illustriert.
Kent Pawar
10

Die Umleitung erfolgt zuerst in der Shell. In Ihrem Beispiel:

cat test.txt > test.txt

Das erste, was passiert, ist das Öffnen von Bash test.txt, wodurch die Datei abgeschnitten wird. Es ist jetzt leer, bevor cates test.txtals Argument ausgeführt wird.

Aus dem Umleitungsbereich der Bash-Manpage:

Bevor ein Befehl ausgeführt wird, können seine Eingabe und Ausgabe unter Verwendung einer von der Shell interpretierten speziellen Notation umgeleitet werden. Die Umleitung kann auch zum Öffnen und Schließen von Dateien für die aktuelle Shell-Ausführungsumgebung verwendet werden. Die folgenden Umleitungsoperatoren können vor oder innerhalb eines einfachen Befehls erscheinen oder einem Befehl folgen. Weiterleitungen werden in der Reihenfolge verarbeitet, in der sie angezeigt werden, von links nach rechts.

Ich sehe in der POSIX-Spezifikation nichts, was darauf hindeutet, dass es zuerst auftreten sollte, aber mir ist keine Shell bekannt, in der dies nicht der Fall ist.

Jordanm
quelle