Das grundlegende Problem, das Sie lösen müssen, ist, wie Sie die Ausführung von time
und die Variablenzuweisung in derselben Shell ohne eine temporäre Datei ausführen können. Beinahe jede Methode, die Bash zur Verfügung stellt, um die Ausgabe einer Sache an eine andere zu leiten, oder die Ausgabe eines Befehls zu erfassen, hat eine Seite, die in einer Unterschale arbeitet. Hier
ist eine Möglichkeit, dies ohne eine temporäre Datei zu tun, aber ich werde Sie warnen, es ist nicht schön, es zu anderen Shells nicht tragbar ist, und es erfordert mindestens Bash 4:
coproc co { cat; }; times 1>&${co[1]}; eval "exec ${co[1]}>&-"; mapfile -tu ${co[0]} times_a
ich werde dies für Sie brechen:
coproc co { cat; }
Dieses eine Koprozeß schafft; ein Prozess, der im Hintergrund abläuft, aber Sie erhalten Rohre, die mit der Standardeingabe und der Standardausgabe kommunizieren. Dies sind die FDs ${co[0]}
(Standard von cat
) und ${co[1]}
(Standard in cat
). Die Befehle werden in einer Subshell ausgeführt, so dass wir dort keines unserer Ziele ausführen können (times
ausführen oder in eine Variable einlesen), aber wir können cat
verwenden, um die Eingabe einfach an die Ausgabe zu übergeben und dann diese Pipe zu verwenden mit times
und mapfile
in der aktuellen Shell zu sprechen.
times >&${co[1]};
Run times
, Umleitung seines Standard in dem cat
Befehl zum Standard werden.
eval "exec ${co[1]}>&-"
Schließen Sie das Eingabeende des Befehls cat
. Wenn wir dies nicht tun, wird cat
weiter auf Eingabe warten, seine Ausgabe bleibt offen, und mapfile
wird weiterhin darauf warten, was dazu führt, dass Ihre Shell hängen bleibt. exec
, wenn keine Befehle übergeben, wendet einfach seine Umleitungen auf die aktuelle Shell; Umleiten zu -
schließt eine FD. Wir müssen eval
verwenden, weil Bash Probleme mit exec ${co[1]}>&-
zu haben scheint, die FD als den Befehl anstelle von Teil der Umleitung interpretierend; Mithilfe von eval
kann diese Variable zuerst ersetzt und dann ausgeführt werden.
mapfile -tu ${co[0]} times_a
Schließlich lesen wir tatsächlich die Daten aus dem Standard aus dem Coprocess. Es ist uns gelungen, den Befehl times
und den Befehl mapfile
in dieser Shell auszuführen und keine temporären Dateien zu verwenden, obwohl wir einen temporären Prozess als Pipeline zwischen den beiden Befehlen verwendet haben.
Beachten Sie, dass dies eine subtile Rasse hat. Wenn Sie diese Befehle nacheinander ausführen, statt alle als einen Befehl, schlägt der letzte fehl. Denn wenn Sie den Standard cat
in schließen, wird der Prozess beendet, wodurch der Coprozess beendet und FDs geschlossen werden. Es scheint, dass, wenn alle auf einer Zeile ausgeführt werden, mapfile
schnell genug ausgeführt wird, dass der Coprozess immer noch geöffnet ist, wenn er ausgeführt wird, und somit aus der Pipe lesen kann; aber vielleicht habe ich Glück. Ich habe keinen guten Weg gefunden.
Alles in allem ist es viel einfacher, nur die temporäre Datei zu schreiben. Ich würde mktemp
verwenden, um einen Dateinamen zu generieren, und wenn Sie in einem Skript sind, fügen Sie eine Falle, um sicherzustellen, dass Sie Ihre temporären Dateien säubern vor dem Verlassen:
tempnam=$(mktemp)
trap "rm '$tempnam'" EXIT
times > ${tempnam}
mapfile -t times_a < ${tempnam}
Ich wünsche ich dies noch upvote könnte, ich habe gelernt, viel lesen das, wirklich nette Antwort! – higuaro