Warum führt die Prozessersetzung zu einer Datei mit dem Namen / dev / fd / 63, die eine Pipe ist?

40

Ich versuche, Named Pipes im Kontext dieses speziellen Beispiels zu verstehen.

Ich tippe <(ls -l)in meinem Terminal und erhalten die Ausgabe als, bash: /dev/fd/63: Permission denied.

Wenn ich tippe cat <(ls -l), könnte ich den Verzeichnisinhalt sehen. Wenn ich die ersetzen catmit echo, ich glaube , ich die Terminalnamen bekommen (oder ist es?).

echo <(ls -l)gibt die Ausgabe als /dev/fd/63.

Auch diese Beispielausgabe ist mir unklar.

ls -l <(echo "Whatever")
lr-x------ 1 root root 64 Sep 17 13:18 /dev/fd/63 -> pipe:[48078752]

Wenn ich jedoch gebe, ls -l <()listet es mir den Verzeichnisinhalt auf.

Was passiert bei der Named Pipe?

Ramesh
quelle

Antworten:

37

Wenn Sie dies tun <(some_command), führt Ihre Shell den Befehl in Klammern aus und ersetzt das Ganze durch einen Dateideskriptor, der mit der Standardausgabe des Befehls verbunden ist. So /dev/fd/63ist eine Pipe, die die Ausgabe Ihres ls-Aufrufs enthält.

Wenn Sie dies tun, erhalten <(ls -l)Sie eine Permission deniedFehlermeldung, da die gesamte Zeile durch die Pipe ersetzt wird und effektiv versucht wird, /dev/fd/63einen Befehl aufzurufen , der nicht ausführbar ist.

In Ihrem zweiten Beispiel cat <(ls -l)wird cat /dev/fd/63. Wenn cat aus den als Parameter angegebenen Dateien liest, erhalten Sie den Inhalt. echoauf der anderen Seite werden nur die Parameter "wie sie sind" ausgegeben.

Der letzte Fall, den Sie haben, <()wird einfach durch nichts ersetzt, da es keinen Befehl gibt. Dies ist jedoch nicht konsistent zwischen Shells, in zsh erhalten Sie immer noch eine Pipe (obwohl leer).

Zusammenfassung : <(command)Hiermit können Sie die Ausgabe eines Befehls verwenden, für den Sie normalerweise eine Datei benötigen.

Edit: Wie Gilles betont, ist dies keine Named Pipe, sondern eine anonyme Pipe. Der Hauptunterschied besteht darin, dass es nur existiert, solange der Prozess ausgeführt wird, während eine Named Pipe (erstellt zB mit mkfifo) ohne damit verbundene Prozesse bleibt.

crater2150
quelle
5
mkfifoErstellt nur die Named Pipe ohne Inhalt. Sie müssen also selbst schreiben (z mkfifo mypipe; ls > mypipe. B. ). Und ja, die Schreibvorgänge in die Pipe werden blockiert, bis ein Prozess aus der Pipe liest.
crater2150
6
Hier gibt es keine Named Pipe. /dev/fd/63ist eine anonyme Pipe.
Gilles 'SO- hör auf böse zu sein'
1
@ crater2150, @Gilles / dev / fd / 63 ist in der Tat eine Named Pipe. Überprüfen Sie dies mit etwas wie file <(ls). Die Shell erstellt zwar eine anonyme Pipe, der Dateideskriptor wird jedoch als Named Pipe in dargestellt /dev/fd. Wenn es sich um eine anonyme Pipe handeln würde, hätte sie keinen Namen und könnte nicht von einem Befehl geöffnet werden, an den sie übergeben /dev/fd/63wird.
rv
2
@rv Es ist immer noch eine anonyme Pipe. Die Tatsache, dass es einen Dateinamen gibt, der auf diese anonyme Pipe verweist, macht sie nicht zu einer benannten Pipe: Eine benannte Pipe ist anders, existiert irgendwo in einem Dateisystem, hat Berechtigungen und Eigentumsrechte usw. Einträge von /dev/fdkönnen auf jede Datei verweisen Deskriptor, sogar anonyme Pipes und Sockets, Netzwerk-Sockets, Shared-Memory-Segmente usw.
Gilles 'SO - hör auf, böse zu sein'
1
Warum ist es aber 63 ?
K3 --- rnc
-4

Sie verstehen den lsBefehl und die Umleitung falsch . lslistet die Dateien und Verzeichnisse auf, die in der Kommandozeile angegeben sind. Ich glaube nicht, dass es Eingaben von stdin akzeptiert. Umleitung > >>und <sind Möglichkeiten, eine Datei zu verwenden, um Eingaben zu machen und Ausgaben zu sammeln.

Rhabarberhund
quelle
1
Hier findet keine Umleitung von einer Datei statt. <(…)ist eine Prozessersetzung.
Gilles 'SO - hör auf böse zu sein'
1
@IMSoP - wie Gilles sagte - es ist keine Named Pipe - es ist eine anonyme Pipe. Es ist sehr ähnlich x|yund fast identisch mit [num]<<REDIRECTeinigen Muscheln. Wo es sich unterscheidet, ist die wörtliche Ersetzung der fd-Verknüpfung durch die Shell - /dev/fd/63und so weiter - und was sie mit stdin macht - oder nicht macht. Machen Sie es sich selbst echo | readlink /dev/fd/0und überzeugen Sie sich.
mikeserv
1
@IMSoP - das ist ein devLink - eine spezielle Datei. Sie können dasselbe mit jedem Dateideskriptor auf den meisten Linux-Systemen tun - sogar typisch |pipes, obwohl ich nicht für das Verhalten an anderer Stelle bürge. Ich verstehe, woher du kommst, aber eine Named Pipe ist eine eigenständige Sache - es ist eine Dateisystemreferenz auf eine In-Kernel-Pipe - eine reguläre Dateisystemreferenz, keine Gerätedatei.
mikeserv
1
@mikeserv Interessanterweise wird im Bash-Handbuch erwähnt, dass es auf Systemen funktioniert, ohne /dev/fd/*dass eine Named Pipe an einer anderen Stelle erstellt wird. Aber ich gehe davon aus, dass es /dev/fd/*sich um einen anderen Mechanismus als eine eigentliche Named Pipe handelt. Übrigens könnte die Beschreibung von Wikipedia eine Erklärung für diese Unterscheidung gebrauchen.
IMSoP
1
@mikeserv Laut anderen Referenzen, die ich gefunden habe, ist es einfacher als das: Wenn /dev/fd/*es nicht verfügbar ist, erstellt bash eine Named Pipe /tmpund verwendet diese stattdessen für die Prozessersetzung. Kommt mir nicht so komisch vor, nur die Funktionalität in so vielen Umgebungen wie möglich verfügbar zu machen.
IMSoP,