Wenn ich an der Befehlszeile arbeite, ertappe ich mich häufig dabei, dass ich dieselbe Operation für eine Reihe verschiedener Instanzen angebe, die durch einen Eingabestream angegeben werden, und dann deren Ausgaben auf eine bestimmte Art und Weise neu kombinieren möchte.
Zwei Anwendungsfälle von gestern:
Ich wollte die Themen einer Reihe von SSL-Zertifikaten sehen, die in einer PEM-Datei gebündelt sind.
cat mypemfile.crt | (openssl x509 -noout -text | fgrep Subject:)
zeigt mir nur das erste an. Ich muss die Zertifikate aufteilen und für jedes davon denselben Befehl ausführen und dann die Ergebnisse verketten.
csplit
kann sie aufteilen, aber nur in Dateien. Das ist mühsam.Warum kann ich nicht einfach sagen
cat mypemfile.crt | csplit-tee '/BEGIN/ .. /END/' | on-each ( openssl x509 -noout -text | fgrep Subject: ) | merge --cat
?
Wir betreiben eine JupyterHub-Instanz, die Notebook-Server als Docker-Container abspaltet. Ich möchte ihre zeitgestempelten Protokolle sehen. Für einen Container ist das ganz einfach:
sudo docker logs -t -f $container_id
(Das
-t
fügt einen Zeitstempel hinzu und das-f
hält die Pipe offen, wietail -f
.)Es ist ganz einfach, die Protokolle aller Container nach Zeitstempeln sortiert aufzulisten:
sudo docker ps | awk '{print $1}' | while read container_id do sudo docker logs -t $container_id done | sort
oder
sudo docker ps | awk '{print $1}' | xargs -n1 sudo docker logs -t | sort
oder
sudo docker ps | awk '{print $1}' | parallel sudo docker logs -t {} | sort
Aber keine dieser Möglichkeiten ermöglicht mir die Nutzung der
-f
Option zum Überwachen der Protokolle beim Eintreffen.Warum kann ich nicht einfach
sudo docker ps | awk '{print $1}' | csplit-tee /./ | on-each (xargs echo | sudo docker logs -t -f) | merge --line-by-line --lexicographically
oder
sudo docker ps | awk '{print $1}' | parallel --multipipe sudo docker logs -t -f {} | merge --line-by-line --lexicographically
?
Dies erfordert natürlich
- Spezifische Shell-Unterstützung. Vielleicht bräuchten wir ein eindeutiges „Multi-Pipe“-Symbol.
- Neue Tools (
csplit-tee
,on-each
undmerge
) zum Aufteilen und Zusammenführen von Pipelines. - Eine feste Konvention zum Angeben beliebig vieler Eingabe- und Ausgabedateideskriptoren innerhalb von Tools, sodass diese Shell sie als parallele Pipelines behandelt.
Wurde dies bereits getan? Oder etwas Gleichwertiges, das ich auf meine Anwendungsfälle anwenden kann?
Ist dies ohne spezifische Kernel-Unterstützung machbar? Ich weiß, dass der Kernel normalerweise eine feste maximale Anzahl offener Dateideskriptoren hat, aber eine Implementierung kann dies umgehen, indem sie nicht blind versucht, sie alle auf einmal zu öffnen.
Ist es machbar, wenn man weiß,GNU parallelist machbar?
Antwort1
Mit GNU Parallel:
cat mypemfile.crt |
parallel --pipe -N1 --recstart '-----BEGIN' 'openssl x509 -noout -text | fgrep Subject:'
Ungetestet:
sudo docker ps | awk '{print $1}' |
sudo parallel -j0 --lb docker logs -t -f {}
sudo docker ps | awk '{print $1}' |
sudo parallel -j0 --tag --lb docker logs -t -f {}
Antwort2
Nein, das kann die Shell nicht. Eine Pipe ist einfach ein Datenstrom von einer Quelle zu einem Ziel, normalerweise in verschiedenen Prozessen.
Schauen wir uns Ihr erstes Beispiel an:
cat mypemfile.crt |
(openssl x509 -noout -text | fgrep Subject:)
Sie möchten, dass die Eingabedatei entlang der Zeilen mit BEGIN und END aufgeteilt wird, cat
der Inhalt ist Ihnen jedoch egal, und Pipes weisen ohnehin keine außerhalb der Grenzen liegenden Angaben zu Datensatztrennzeichen auf.
Dies ließe sich zwar durch spezielle Konventionen in der Quelle und dem Ziel einer Pipe erreichen, allerdings ginge dadurch der Hauptvorteil einer Pipe verloren, nämlich die Möglichkeit, Programme als Bausteine für Aufgaben zu kombinieren, die von ihren Autoren nicht vorhergesehen wurden.
In diesem speziellen Beispiel wäre es viel einfacher, die Änderung so vorzunehmen, openssl
dass mehrere Zertifikate in einem Stream verarbeitet werden, als die Änderung so vorzunehmen, openssl
dass mehrere Streams verarbeitet werden UND diese Änderung so vorzunehmen, cat
dass diese mehreren Streams bereitgestellt werden.