Ein guter Weg, um den Unterschied zwischen ihnen herauszufinden, besteht darin, ein wenig in der Befehlszeile zu experimentieren. Trotz der visuellen Ähnlichkeit bei der Verwendung des <
Zeichens unterscheidet es sich erheblich von einer Umleitung oder Pipe.
Verwenden wir den date
Befehl zum Testen.
$ date | cat
Thu Jul 21 12:39:18 EEST 2011
Dies ist ein sinnloses Beispiel, aber es zeigt, dass cat
die Ausgabe von date
auf STDIN akzeptiert und wieder ausgespuckt wurde. Die gleichen Ergebnisse können durch Prozesssubstitution erzielt werden:
$ cat <(date)
Thu Jul 21 12:40:53 EEST 2011
Was jedoch gerade hinter den Kulissen geschah, war anders. Anstatt einen STDIN-Stream zu erhalten, cat
wurde tatsächlich der Name einer Datei übergeben, die geöffnet und gelesen werden musste. Sie können diesen Schritt sehen, indem Sie echo
anstelle von verwenden cat
.
$ echo <(date)
/proc/self/fd/11
Als cat den Dateinamen erhielt, las sie den Inhalt der Datei für uns. Auf der anderen Seite zeigte uns Echo nur den Namen der Datei, dass sie übergeben wurde. Dieser Unterschied wird deutlicher, wenn Sie weitere Substitutionen hinzufügen:
$ cat <(date) <(date) <(date)
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
Thu Jul 21 12:44:45 EEST 2011
$ echo <(date) <(date) <(date)
/proc/self/fd/11 /proc/self/fd/12 /proc/self/fd/13
Es ist möglich, die Prozessersetzung (die eine Datei generiert) und die Eingabeumleitung (die eine Datei mit STDIN verbindet) zu kombinieren:
$ cat < <(date)
Thu Jul 21 12:46:22 EEST 2011
Es sieht ziemlich ähnlich aus, aber dieses Mal wurde cat der STDIN-Stream anstelle eines Dateinamens übergeben. Sie können dies sehen, indem Sie es mit echo versuchen:
$ echo < <(date)
<blank>
Da das Echo STDIN nicht liest und kein Argument übergeben wurde, erhalten wir nichts.
Pipes und Eingabeumleitungen leiten Inhalte in den STDIN-Stream. Die Prozessersetzung führt die Befehle aus, speichert ihre Ausgabe in einer speziellen temporären Datei und übergibt diesen Dateinamen anstelle des Befehls. Bei jedem Befehl, den Sie verwenden, wird er als Dateiname behandelt. Beachten Sie, dass die erstellte Datei keine reguläre Datei ist, sondern eine Named Pipe, die automatisch entfernt wird, sobald sie nicht mehr benötigt wird.
[[ -p <(date) ]] && echo true
. Dies ergibt sich,true
wenn ich es mit Bash 4.4 oder 3.2 starte.Ich nehme an, Sie sprechen von einer
bash
oder einer anderen erweiterten Shell, da die posix-Shell keine Prozessersetzung enthält .bash
Man-Page-Berichte:Mit anderen Worten und aus praktischer Sicht können Sie einen Ausdruck wie den folgenden verwenden
als Dateiname für andere Befehle, für die eine Datei als Parameter erforderlich ist. Oder Sie können die Umleitung für eine solche Datei verwenden:
Zurück zu Ihrer Frage: Prozessersetzung und Pipes haben meines Erachtens nicht viel gemeinsam.
Wenn Sie die Ausgabe mehrerer Befehle nacheinander weiterleiten möchten, können Sie eine der folgenden Formen verwenden:
Sie können aber auch die Umleitung für die Prozessersetzung verwenden
schließlich, wenn
command3
ein Dateiparameter akzeptiert wird (anstelle von stdin)quelle
Hier sind drei Dinge, die Sie mit der Prozessersetzung tun können, die sonst unmöglich sind.
Mehrere Prozesseingänge
Mit Rohren geht das einfach nicht.
STDIN erhalten
Angenommen, Sie haben Folgendes:
Und Sie möchten es direkt ausführen. Das Folgende scheitert kläglich. Bash verwendet bereits STDIN zum Lesen des Skripts, sodass andere Eingaben nicht möglich sind.
Aber dieser Weg funktioniert einwandfrei.
Ausgehende Prozessersetzung
Beachten Sie auch, dass die Prozessersetzung auch umgekehrt funktioniert. Sie können also so etwas tun:
Das ist ein verworrenes Beispiel, aber es sendet stdout an
/dev/null
, während stderr an ein sed-Skript weitergeleitet wird, um die Namen der Dateien zu extrahieren, für die der Fehler "Berechtigung verweigert" angezeigt wurde, und sendet dann DIESE Ergebnisse an eine Datei.Beachten Sie, dass der erste Befehl und die stdout- Umleitung in Klammern ( Subshell ) angegeben sind, sodass nur das Ergebnis des Befehls THAT an gesendet wird
/dev/null
und der Rest der Zeile nicht beeinträchtigt wird.quelle
diff
Beispiel , das Sie vielleicht über den Fall kümmern wollen , wo diecd
fehlschlagen könnten:diff <(cd /foo/bar/ && ls) <(cd /foo/baz && ls)
.Wenn ein Befehl eine Liste von Dateien als Argumente verwendet und diese Dateien als Eingabe (oder Ausgabe, aber nicht allgemein) verarbeitet, kann jede dieser Dateien eine Named Pipe oder eine / dev / fd-Pseudodatei sein, die transparent durch die Prozesssubstitution bereitgestellt wird:
Dies leitet die Ausgabe der drei Befehle zum Sortieren weiter, da sort eine Liste von Eingabedateien in der Befehlszeile aufnehmen kann.
quelle
<()
, wie viele erweiterte Shell-Funktionen, ursprünglich eine ksh-Funktion und wurde von bash und zsh übernommen.psub
ist speziell ein Fisch-Feature, das nichts mit POSIX zu tun hat.Es ist zu beachten, dass die Prozessersetzung nicht auf das Formular beschränkt ist
<(command)
, das die Ausgabe voncommand
als Datei verwendet. Es kann in der Form vorliegen, in>(command)
die eine Datei als Eingabe eingespeist wirdcommand
. Dies wird auch im Zitat des Bash-Handbuchs in der Antwort von @enzotib erwähnt.Für das
date | cat
obige Beispiel wäre ein Befehl, der die Prozessersetzung des Formulars verwendet>(command)
, um den gleichen Effekt zu erzielen,Beachten Sie, dass das
>
Vorherige>(cat)
erforderlich ist. Dies lässt sich wiederum deutlich anhandecho
der Antwort von @ Caleb veranschaulichen .Also, ohne die zusätzlichen
>
,date >(cat)
wäre das gleiche wiedate /dev/fd/63
die eine Nachricht an stderr gedruckt wird.Angenommen, Sie haben ein Programm, das nur Dateinamen als Parameter verwendet und nicht
stdin
oder verarbeitetstdout
. Ich werde das vereinfachte Skript verwendenpsub.sh
, um dies zu veranschaulichen. Der Inhalt vonpsub.sh
istGrundsätzlich prüft es , dass beide ihre Argumente sind Dateien (nicht unbedingt reguläre Dateien) , und wenn dies der Fall ist, schreiben Sie das erste Feld jeder Zeile
"$1"
zu"$2"
verwenden awk. Dann ist ein Befehl, der alles bisher Erwähnte kombiniert,Dies wird gedruckt
und ist äquivalent zu
aber das Folgende wird nicht funktionieren, und wir müssen hier Prozesssubstitution verwenden,
oder seine äquivalente Form
Wenn außer dem oben Erwähnten
./psub.sh
auch gelesenstdin
wird, gibt es kein entsprechendes Formular, und in diesem Fall können wir anstelle der Prozessersetzung nichts verwenden (natürlich können Sie auch eine Named Pipe- oder temporäre Datei verwenden, aber das ist eine andere Geschichte).quelle