Verhindern Sie automatische EOFs an eine Named Pipe und senden Sie eine EOF, wenn ich dies möchte

12

Ich habe ein Programm, das beim Lesen eines EOF in einem bestimmten Stream automatisch beendet wird (im folgenden Fall stdin).
Jetzt möchte ich ein Shell-Skript erstellen, das eine Named Pipe erstellt und den Standard des Programms damit verbindet. Anschließend schreibt das Skript mehrmals mit echound cat(und anderen Tools, die beim Beenden automatisch einen EOF generieren) in die Pipe . Das Problem, mit dem ich konfrontiert bin, ist, dass wenn das erste echoerledigt ist, ein EOF an die Pipe gesendet wird und das Programm beendet wird. Wenn ich so etwas verwende, kann tail -fich keine EOF senden, wenn ich beabsichtige, das Programm zu beenden. Ich suche nach einer ausgewogenen Lösung, aber ohne Erfolg.
Ich habe bereits herausgefunden, wie man EOFs verhindert und wie man einen EOF manuell sendet, aber ich kann sie nicht kombinieren. Gibt es einen Hinweis?

#!/bin/sh
mkfifo P
program < P & : # Run in background
# < P tail -n +1 -f | program
echo some stuff > P # Prevent EOF?
cat more_stuff.txt > P # Prevent EOF?
send_eof > P # How can I do this?
# fg
iBug
quelle

Antworten:

13

Wie andere angegeben haben, erhält der Leser einer Pipe EOF, sobald keine Autoren mehr vorhanden sind. Die Lösung besteht also darin, sicherzustellen, dass immer ein Autor sie offen hält. Dieser Autor muss nichts senden, sondern nur offen halten.

Da Sie ein Shell-Skript verwenden, besteht die einfachste Lösung darin, die Shell anzuweisen, die Pipe zum Schreiben zu öffnen. Und schließen Sie es, wenn Sie fertig sind.

#!/bin/sh
mkfifo P
exec 3>P # open file descriptor 3 writing to the pipe
program < P
# < P tail -n +1 -f | program
echo some stuff > P
cat more_stuff.txt > P
exec 3>&- # close file descriptor 3

Wenn Sie die letzte Zeile weglassen, wird der Dateideskriptor 3 beim Beenden des Skripts automatisch geschlossen (und der Leser erhält EOF). Abgesehen von der Bequemlichkeit bietet dies auch eine Art Sicherheit, wenn das Skript irgendwie vorzeitig beendet wird.

Patrick
quelle
2
diese exec 3>PUrsache hängen in Bash, warum?
Wang
@ Wang Es sollte nicht. Wenn dies der Fall ist, tun Sie wahrscheinlich nicht das Gleiche wie der POC-Code in der Frage. Der einzige Grund, warum ich denken kann, dass es blockieren würde, ist, wenn Sie stattdessen so etwas tun exec 2>Pund den Trace-Modus aktiviert haben ( set -x), in dem Bash in die Pipe schreiben wird, aber es gibt keinen Leser, so dass das Warten blockiert etwas zu lesen.
Patrick
1
@ Wang @ Patrick In der Tat exec 3>Phängt in Bash auch auf meinem Computer. Dies liegt daran, dass kein Prozess von gelesen wird P. Daher bestand die Lösung darin, Zeilen auszutauschen exec 3>Pund program < P &(das kaufmännische Und hinzuzufügen, damit das Programm im Hintergrund ausgeführt wird).
Macieksk
2

Eine Pipe erhält EOF, wenn der letzte Schreiber weggeht. Um dies zu vermeiden, stellen Sie sicher, dass immer ein Writer vorhanden ist (ein Prozess, bei dem die Pipe zum Schreiben geöffnet ist, der jedoch nichts schreibt). Um die EOF zu senden, lassen Sie diesen Reserveschreiber verschwinden.

mkfifo P
while sleep 1; do :; done >P &
P_writer_pid=$!
send_eof_to_P () {
  kill $P_writer_pid
}
Gilles 'SO - hör auf böse zu sein'
quelle
0

Es gibt keine Möglichkeit für das Programm, zwischen einer EOF zu unterscheiden, die "es ist Zeit zu beenden" bedeutet, und einer EOF, die bedeutet, dass "ein Autor fertig ist, aber möglicherweise mehr Eingaben von jemand anderem".

Wenn Sie das Verhalten Ihres Programms ändern können, lesen Sie in einer Endlosschleife (eine Iteration dauert bis EOF) und senden Sie eine bestimmte Befehlszeichenfolge, die "Zeit zum Beenden" bedeutet. Das Senden dieser Zeichenfolge wäre die Aufgabe des send_eofBefehls in Ihrer Frage.

Andere Option:

( echo some stuff; cat more_stuff.txt ) >P

oder

{ echo some stuff; cat more_stuff.txt; } >P
Kusalananda
quelle