Hi Folks,
die man-Page von bash sagt zu read:<blockquote><hr>-t timeout
Cause read to time out and return failure if
a complete line of input is not read within
timeout seconds. This option has no effect
if read is not reading input from the termi-
nal or a pipe.
<hr></blockquote>
Genau was ich brauche - nur klappt es leider nicht. Ein an der Shell getipptes <pre>read -t 1 JUNK</pre>kommt nach 1 sec zurück, Exitcode 1, JUNK ist leer. Ein<pre>(sleep 5 ; echo hallo ) | read -t 1 JUNK</pre>sollte auch nach 1 sec zurückkommen - tut es aber nicht. Statt dessen dauert es 5 Sekunden, Exitcode ist immer noch 1 und JUNK ist leer.
(Im echten Leben wollte ich aus einer Named Pipe lesen - ohne Timeout bleibt das Skript hängen, bis jemand in die Pipe schreibt. Dem wollte ich mit dem Timeout eigentlich entkommen.)
Weiss jemand, ob das so gewollt ist? Im Prinzip hat das read ja einen Timeout - es kehrt halt erst nach Ende des letzten Kommandos in der Pipeline zurück. Oder fällt das unter Bug/Feature? Eine erste Recherche per Google hat zwar einige Lösungsansätze für das Problem ergeben, aber nirgends habe ich einen Hinweis auf dieses Verhalten gefunden.
Bin für alle Meldungen dankbar,
Jochen
<i>grummel</i> Is ja klar, dass man immer was vergisst: bash Version 2.0.5 bzw 2.0.5b.
J
bash: read mit Timeout
bash: read mit Timeout
Last edited by jochen on 07. Oct 2002 14:41, edited 1 time in total.
Re: bash: read mit Timeout
Die schlechte Nachricht ist, dass das o.a. Problem nicht gelöst ist.
Die gute Nachricht ist, dass es einen Workaround gibt. <img src="http://www.pl-forum.de/UltraBoard/Images/Happy.gif" border="0" align="middle">
<blockquote><pre><font size="1" face="">code:</font><hr><font face="Courier New" size="2">
#!/bin/bash
# Skript: timeout_read
# Argument: Zeit in Sekunden bis zum Timeout
# Ausgabe: Die von stdin gelesene Eingabe wird auf stdout geschrieben
# Exitcode: enspricht Exitcode von read, 10 bei Timeout
# SIGUSR1 wird bei Timeout erhalten, dann beenden mit Timeout-Exitcode
trap 'exit 1' 10
# Schläferprozess, der den Timeout implementiert. Schickt SIGUSR1 an die Eltern-Shell nach
# Ablauf des Timeouts.
( sleep $1 ; kill -USR1 $$ ) &>/dev/null &
# Eingabe lesen, Exitcode für Ende des Skripts merken
read INP
EXITCODE=$?
# Wenn wir hier ankommen, hat read etwas gelesen, bevor der Timeout-Job zugeschlagen hat.
# Daher den Timeout-Job killen, Eingabe ausgeben und Schluss.
kill $! &>/dev/null
echo "$INP"
exit $EXITCODE
</font><hr></pre></blockquote>Dies ist die Minimal-Version, man sollte ggf. das Argument noch checken usw. Aber so geht es wenigstens erst mal. Anwendung beispielsweise so:<pre>VAR=$(timeout_read 5)</pre>Jochen
Die gute Nachricht ist, dass es einen Workaround gibt. <img src="http://www.pl-forum.de/UltraBoard/Images/Happy.gif" border="0" align="middle">
<blockquote><pre><font size="1" face="">code:</font><hr><font face="Courier New" size="2">
#!/bin/bash
# Skript: timeout_read
# Argument: Zeit in Sekunden bis zum Timeout
# Ausgabe: Die von stdin gelesene Eingabe wird auf stdout geschrieben
# Exitcode: enspricht Exitcode von read, 10 bei Timeout
# SIGUSR1 wird bei Timeout erhalten, dann beenden mit Timeout-Exitcode
trap 'exit 1' 10
# Schläferprozess, der den Timeout implementiert. Schickt SIGUSR1 an die Eltern-Shell nach
# Ablauf des Timeouts.
( sleep $1 ; kill -USR1 $$ ) &>/dev/null &
# Eingabe lesen, Exitcode für Ende des Skripts merken
read INP
EXITCODE=$?
# Wenn wir hier ankommen, hat read etwas gelesen, bevor der Timeout-Job zugeschlagen hat.
# Daher den Timeout-Job killen, Eingabe ausgeben und Schluss.
kill $! &>/dev/null
echo "$INP"
exit $EXITCODE
</font><hr></pre></blockquote>Dies ist die Minimal-Version, man sollte ggf. das Argument noch checken usw. Aber so geht es wenigstens erst mal. Anwendung beispielsweise so:<pre>VAR=$(timeout_read 5)</pre>Jochen
Re: bash: read mit Timeout
Zum guten Schluss: Der o.a. Work-Around ist zwar funktionsfähig, nützt aber nichts, da das Problem an anderer Stelle liegt. Am Rand hatte ich erwähnt, dass ich aus einer Named Pipe lesen wollte - <b>das</b> war das Problem. Solange kein Prozess die FIFO zum Schreiben geöffnet hat, werden lesende Prozesse direkt blockiert. Dies dient zur Synchronisation der Prozesse untereinander. Endgültige Lösung des Problems: Direkt nach Erstellen des FIFOs einen Prozess anlegen, der nix weiter tut als den FIFO offen zu halten.<pre>(while true ; do sleep 3600 ; done) <> $FIFO &</pre>Wenn dann das Programm beendet werden soll, einfach beim Aufräumen ein "fuser -k $FIFO" machen, und der Dummy-Prozess wird abgeschossen.
Jochen
Jochen
Re: bash: read mit Timeout
Hi!
> Wenn dann das Programm beendet werden soll, einfach beim Aufräumen ein
> "fuser -k $FIFO" machen, und der Dummy-Prozess wird abgeschossen.
Das muss sich doch auch automatisieren lassen, oder?
Cheers,
GNU/Wolfgang
> Wenn dann das Programm beendet werden soll, einfach beim Aufräumen ein
> "fuser -k $FIFO" machen, und der Dummy-Prozess wird abgeschossen.
Das muss sich doch auch automatisieren lassen, oder?
Cheers,
GNU/Wolfgang
Re: bash: read mit Timeout
Nun ja klar! Beim Erstellen der FIFO wird der "Aufhalte"-Prozess erzeigt, beim Löschen wie o.a. mittels fuser -k gekillt. Also alles in 2 bash-Funktionen create_fifo und delete_fifo gepackt und gut ist. Damit liegt der FIFO (plus Prozess zum offen halte) auch nicht ständig herum, sondern wird immer nach Bedarf erstellt/gelöscht.
Jochen
Jochen