Ich habe ein Bash-Skript, das eine Funktion aufruft. Die Funktion führt unter anderem eine Pipeline aus, die ihre Ausgabe verarbeitet. Um es zu vereinfachen, hier ein konstruiertes Beispiel:
#!/bin/bash
func() {
ls "$@" | sort | rev > /tmp/output
}
func "$@"
Sie würden dann etwas wie das Folgende tun, um es auszuführen. Es würde seine Arbeit erledigen und seine Nutzlast in eine Datei übertragen. Es erfolgt keine Ausgabe auf dem Bildschirm.
$ ./myscript .
Angenommen, ich möchte die Ausgabe sort
auf der Standardausgabe. Wie würde ich das tun?
Ich kann es so erreichen:
ls "$@" | sort | tee /dev/tty | rev > /tmp/output
Die Verwendung ist jedoch /dev/tty
falsch, da dies nicht funktioniert:
$ ./myscript > myfile
Gibt es eine korrektere Möglichkeit, innerhalb einer Pipeline innerhalb einer Funktion auf die Standardausgabe eines Bash-Skripts zu verweisen?
(Ich verwende Bash 4.3.0 unter Arch Linux)
Antwort1
Der einfachste Weg, der mir hierfür einfällt, ist:
ls "$@" | sort | tee >(rev > /tmp/output)
Das tee
sendet eine Kopie an STDOUT, und da danach kein mehr folgt |
, wird dies übernommen, d. h. es geht an das TTY, wenn es nicht umgeleitet wird, und an Ihr, myfile
wenn es umgeleitet wird.
Die andere Kopie wird an rev > /tmp/output
an dessen STDIN gesendet. In Bash >(...)
führt es alles aus, was zwischen den Klammern steht, und ersetzt dann das >(...)
durch den Pfad zu einer Pipe, die mit seinem STDIN verbunden ist.
Antwort2
Da die andere Antwort diesbezüglich nicht klar ist, ist der andere (andere) Weg
exec 3>&1
ls | sort | tee /dev/fd/3 | rev > /tmp/output
Derexec 3>&1
dupkompiliert Dateideskriptor 1 (stdout) als Dateideskriptor 3. Dann tee /dev/fd/3
schreibt es eine Kopie der sort
Ausgabe von in diesen Dateideskriptor. Dies sollte in jeder Shell funktionieren, kann aber vom Betriebssystem abhängen. Eine Variante, die betriebssystemunabhängig, aber bash
-spezifisch sein sollte, ist:
exec 3>&1
ls | sort | tee >( cat >&3 ) | rev > /tmp/output
In erhalten Sie einen Datei-Handle zu einer Pipe zu einem laufenden Prozess bash
.>(command)
command
. In jeder (?) Shell läuftcommand >&fd
command
wobei seine Standardausgabe zum angegebenen Dateideskriptor umgeleitet wird, der zuvor eingerichtet worden sein muss.
Eine kompliziertere Version, die auf jedem *nix (Posix)-System funktionieren sollte, ist
pipe_to_stdout=$(mktemp -u)
mkfifo "$pipe_to_stdout"
cat "$pipe_to_stdout" &
ls | sort | tee "$pipe_to_stdout" | rev > /tmp/output
rm "$pipe_to_stdout"
Das ist so ziemlich dasselbe wie das zweite Beispiel (das cat
Lesen aus dem FIFO und das Schreiben in die Standardausgabe), aber mit weniger Blendwerk auf der Shell-Ebene.
Beachten Sie, dass diese Antworten flexibel sind, d. h. Sie können die Ausgabe ls
einfach durch Neuanordnen der Befehle in die Standardausgabe schreiben.