<(cmd)
ist ein ksh
Funktion, die heutzutage auch in zsh
zu finden ist und bash
genannt Prozesssubstitution .
Auf Systemen, die /dev/fd/n
unterstützen oder /proc/self/fd/n
, wird es mit Pipes implementiert und wenn nicht mit temporären benannten Pipes. Auf jeden Fall ist es eine Art Pipe, die ein Kommunikationsmechanismus zwischen Prozessen ist.
cmd1 <(cmd2)
Kann geschrieben werden (mit normalen Pipes):
{ cmd2 4<&- | 3<&0 <&4 4<&- cmd1 /dev/fd/3; } 4<&0
Oder (mit Named Pipes):
mkfifo /tmp/named_pipe
cmd2 > /tmp/named_pipe & cmd1 /tmp/named_pipe
Das heißt, beide Befehle werden gleichzeitig gestartet und kommunizieren mit einer Pipe. Normalerweise würden Sie cmd2 | cmd1
verwenden dafür, aber Prozessersetzungen sind typischerweise für die Fälle, in denen cmd1
kann nur Eingaben von einem Dateinamen entgegennehmen und nicht von der Standardeingabe oder wenn mehr als eine Eingabe benötigt wird, wie in diff <(cmd1) <(cmd2)
.
Es gibt keine rlimits, die es beeinflussen, außer allgemeine, wie die Anzahl der Prozesse, die CPU-Zeit oder der Speicher.
Der PIPEBUF, der von einigen Implementierungen von ulimit
gemeldet wird wie bash
und einige Implementierungen von ksh
ist kein rlimit, aber die maximale Größe, für die ein Schreiben in eine Pipe garantiert atomar ist, ist hier irrelevant. Die Größe der Pipe selbst (64 KB unter Linux, wie von @dsmsk80 gemeldet) ist an sich keine wirkliche Grenze. Es sagt nur, dass das genauso viel ist cmd2
kann auch nach cmd1
in die Pipe schreiben hat aufgehört daraus zu lesen.
Es gibt jedoch eine Einschränkung in diesem cmd1
dürfen nur lesen aus dieser Datei. Da es sich um eine Pipe handelt, kann es nicht in diese Datei schreiben oder in der Datei hin und her suchen.
zsh
hat eine dritte Form der Befehlsersetzung unter Verwendung regulärer temporärer Dateien:
cmd1 =(cmd2)
ruft cmd1
auf mit einer temporären Datei, die die Ausgabe von cmd2
enthält . In diesem Fall cmd1
wird nach ausgeführt cmd2 statt gleichzeitig. Dort kann das Limit der Dateigröße erreicht werden.
Ich kenne keine Shell, die einen <<<(...)
implementiert Operator. Es gibt jedoch einen <<<
Operator in zsh
(inspiriert vom selben Operator in der Unix-Portierung von rc
) auch in neueren Versionen von ksh93
zu finden und bash
. Es ist eine Variation des <<
Heredoc-Operator namens Herestring.
In:
cmd <<< something
Welches ist dasselbe wie der Standard:
cmd << EOF
something
EOF
Die Shell erstellt eine temporäre Datei mit something\n
als Inhalt und füttert diesen als Standardeingabe in einen neuen Prozess, hebt die Verknüpfung dieser Datei auf und führt cmd
aus in diesem neuen Prozess. Auch hier handelt es sich um eine normale Datei, sodass das rlimit für die maximale Größe einer Datei erreicht werden kann.
Jetzt können Sie den <<<
kombinieren Operator mit $(...)
(Befehlsersetzung), um zsh
irgendwie zu emulieren ist =(...)
Operator in bash
und ksh93
:
cmd1 <<<"$(cmd2)"
Würde cmd2
ausführen damit wird stdout zu einer Pipe umgeleitet. Am anderen Ende der Pipe liest die Shell die Ausgabe von cmd2
und speichert es abzüglich der abschließenden Zeilenumbruchzeichen und mit einem hinzugefügten Zeilenumbruchzeichen in einer temporären Datei und ruft cmd1
auf mit dieser temporären Datei, die zum Lesen als stdin geöffnet ist (beachten Sie, dass es eine weitere Einschränkung gibt, dass es nicht funktioniert, wenn cmd2
Ausgabe enthält NUL-Zeichen).
So zu sein wie =(...)
, müssten Sie es schreiben:
cmd1 /dev/fd/3 3<<<"$(cmd3)"
Beachten Sie, dass die Shell die gesamte Ausgabe von cmd3 im Speicher lesen muss, bevor sie in die temporäre Datei geschrieben wird, sodass Sie zusätzlich zur maximalen Dateigröße möglicherweise auch die Grenze der Speichernutzung erreichen.
Beachten Sie auch, dass seit Version 5 bash
entzieht der temporären Datei die Schreibrechte, bevor cmd1
aufgerufen wird , wenn Sie also cmd1
benötigen Um diese Datei ändern zu können, müssten Sie sie umgehen mit:
{
chmod u+w /dev/fd/3 && # only needed in bash 5+
cmd1 /dev/fd/3
} 3<<<"$(cmd3)"
Bash-Prozessersetzung in Form von <(cmd)
und >(cmd)
wird mit benannten Pipes implementiert, wenn das System sie unterstützt. Der Befehl cmd
wird so betrieben, dass sein Ein-/Ausgang mit einer Rohrleitung verbunden ist. Wenn Sie z. cat <(sleep 10; ls)
Sie finden die erstellte Pipe unter dem Verzeichnis /proc/pid_of_cat/fd
. Diese benannte Pipe wird dann als Argument an den aktuellen Befehl übergeben (cat
).
Die Pufferkapazität einer Pipe kann mit einer kniffligen Verwendung von dd
abgeschätzt werden Befehl, der Nulldaten an die Standardeingabe von sleep
sendet Befehl (der nichts tut). Anscheinend wird der Prozess einige Zeit schlafen, damit der Puffer voll wird:
(dd if=/dev/zero bs=1 | sleep 999) &
Warten Sie eine Sekunde und senden Sie dann USR1
Signal an dd
Prozess:
pkill -USR1 dd
Dadurch wird der Prozess zum Ausdrucken von E/A-Statistiken veranlasst:
65537+0 records in
65536+0 records out
65536 bytes (66 kB) copied, 8.62622 s, 7.6 kB/s
In meinem Testfall ist die Puffergröße 64kB
(65536B
).
Wie verwenden Sie <<<(cmd)
Erweiterung? Mir ist bekannt, dass es sich um eine Variation dieser Dokumente handelt, die erweitert und über die Standardeingabe an den Befehl übergeben wird.
Hoffentlich habe ich etwas Licht in die Frage nach der Größe gebracht. Bezüglich der Geschwindigkeit bin ich mir nicht so sicher, aber ich würde davon ausgehen, dass beide Methoden einen ähnlichen Durchsatz liefern können.