GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Erstellen einer temporären Datei vs. Prozesssubstitution vs. Variablenerweiterung?

<(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.


Linux
  1. TCPdump filtern:Ordnung aus Chaos schaffen

  2. Eine Anleitung für Anfänger zum Erstellen von Weiterleitungen in einer .htaccess-Datei

  3. Wie kann man feststellen, welcher Prozess eine Datei erstellt?

  4. Prozesssubstitution und Pipe?

  5. Variable mit oder ohne Export definieren

Erstellen einer Webzertifikat-CSR-Datei.

Warum funktioniert die Bash-Prozesssubstitution bei einigen Befehlen nicht?

Wie verzögere ich die Variablenerweiterung?

Die Ausgabe der Prozesssubstitution ist nicht in Ordnung?

Erstellen einer leeren Datei mit einem Variablennamen in einem Skript?

Ersetzung von Umgebungsvariablen in sed