
In einem Shell-Skript möchte ich mithilfe einer benannten Pipe in die Standardeingabe eines externen Prozesses X schreiben und die Standardausgabe/Standardfehlerausgabe von einer anderen benannten Pipe an das aktuelle Terminal senden.
Der externe Prozess X empfängt stdin über PIPEIN und sendet sein stdout/stderr an PIPEOUT.
tail -f $(tail -F PIPEOUT) & # (1) this is completely wrong, need help here
for i; do
echo "${i}" > PIPEIN # send stdin to X
done
echo "[stdin end]" > PIPEIN # signal that we are done writing (there might be a better way lol)
Im obigen Skript haben wir also Prozess X bereits gestartet, er läuft schon seit einiger Zeit. Aber jetzt, wenn wir das obige Skript ausführen, möchten wir X eine Standardeingabe senden und die Standardausgabe von Prozess X mithilfe von PIPEOUT einlesen.
Was ich oben versuche, ist, ein Lesen auf PIPEOUT einzurichten, bevor ich stdin an X sende, um sicherzustellen, dass ich alle stdout/stderr von X erfasse. Das Problem besteht darin, dass ich nicht weiß, wie ich einen Hintergrundprozess (tail oder cat zum Lesen von PIPEOUT) ausführen und dieses stdio an das aktuelle Terminal senden kann.
Weiß jemand, wovon ich spreche? Wenn ich mich nicht irre, muss ich nur die Zeile mit der Bezeichnung (1) korrigieren und irgendwie einen Lesevorgang im Hintergrund einrichten, der von PIPEOUT lesen und dieses stdio irgendwie an das aktuelle Terminal/TTY senden kann.
Antwort1
Mir ist nicht klar, was Sie tail -f $(tail -F PIPEOUT) &
tun wollten. Es ist tail -f
das ing der Datei, dieist das Ergebnis von tail -F
, das normalerweise nie beendet wird. Ich gehe davon aus, dass Sie alles ausgeben möchten, was durch die Pipe kommt, egal wie lange das dauert.
Das Problem mit just tail -f
ist, dass es das Ende der Datei finden muss, bevor es etwas ausgibt, was bei der Pipe nie passiert. Sie könnenGeben Sie tail
stattdessen einen expliziten Startpunkt an mit-n +x
, Auswahl der Startzeile (vom Anfang an, 1-indiziert). tail -n 1 -f foo
zeigt alles an, was es von bekommen kann foo
.
tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
for i in a b c d ; do
echo $i > PIPEIN
done
echo "[stdin end]" > PIPEIN
Beachten Sie jedoch, dass echo > foo
foo nach dem Schreiben der Zeile geschlossen wird – der Befehl am anderen Ende muss damit klarkommen. Wenn dieses Beispiel künstlich ist und die eigentliche Eingabe von woanders kommt, können Sie dies ignorieren.
Beachten Sie auch, dassDer tail
Prozess wird niemals beendet— es erwartet immer, dass noch etwas durch die Pipe kommt. Sie müssen es explizit selbst beenden, vielleicht mit der Jobsteuerung Ihrer Shell. Wenn es ein Muster in der Ausgabe gibt, das darauf hinweist, dass es beendet wurde, finden Sie möglicherweiseretail
("tail mit regulären Ausdrücken")nützlich — retail -n +1 -f -u REGEX PIPEOUT
wird beendet, wenn eine Zeilenübereinstimmung REGEX
auftritt. (Als Haftungsausschluss habe ich retail
vor mehreren Jahren genau zu diesem Zweck geschrieben)
Antwort2
Durch das einmalige Öffnen von PIPEIN zum Schreiben wird das Programm beendet – auch wenn es eine Verzögerung von 2 Sekunden gibt:
mkfifo PIPEIN PIPEOUT
tr 'a-z' 'A-Z' < PIPEIN > PIPEOUT & # for example
tail -n +1 -f PIPEOUT &
(
for i in a b c d ; do
echo $i
done
sleep 2
echo "[stdin end]"
) > PIPEIN
Wenn Sie das FIFO mehrmals öffnen, wird es vom Leser des FIFO möglicherweise als geschlossen angesehen, und der Schreiber bleibt hängen, bis ein anderer Leser kommt, um aus dem FIFO zu lesen.
Die sichere Methode besteht also darin, PIPEIN nur einmal zu öffnen. Andernfalls kann es passieren, dass das Programm abstürzt.