bash: read mit Timeout

Post Reply
Message
Author
User avatar
jochen
prolinux-forum-admin
Posts: 699
Joined: 14. Jan 2000 15:37
Location: Jülich
Contact:

bash: read mit Timeout

#1 Post by jochen »

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
Last edited by jochen on 07. Oct 2002 14:41, edited 1 time in total.

User avatar
jochen
prolinux-forum-admin
Posts: 699
Joined: 14. Jan 2000 15:37
Location: Jülich
Contact:

Re: bash: read mit Timeout

#2 Post by jochen »

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

Jochen

Re: bash: read mit Timeout

#3 Post by Jochen »

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

Wolfgang

Re: bash: read mit Timeout

#4 Post by Wolfgang »

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

Jochen

Re: bash: read mit Timeout

#5 Post by Jochen »

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

Post Reply