How to use Bash read with a timeout?

Solution 1:

In bash, read has a -t option where you can specify a timeout. From the manpage:

read [-ers] [-u fd] [-t timeout] [-a aname] [-p prompt] [-n nchars] [-d delim] [name ...]

-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 terminal or a pipe.

Transcript below (without hitting ENTER):

$ date ; read -t 10 -p "Hit ENTER or wait ten seconds" ; echo ; date
Tue Feb 28 22:29:15 WAST 2012
Hit ENTER or wait ten seconds
Tue Feb 28 22:29:25 WAST 2012

Another, hitting ENTER after a couple of seconds:

$ date ; read -t 10 -p "Hit ENTER or wait ten seconds" ; date
Tue Feb 28 22:30:17 WAST 2012
Hit ENTER or wait ten seconds
Tue Feb 28 22:30:19 WAST 2012

And another, hitting CTRL-C:

$ date ; read -t 10 -p "Hit ENTER or wait ten seconds" ; echo ; date
Tue Feb 28 22:30:29 WAST 2012
Hit ENTER or wait ten seconds

Solution 2:

The read builtin has a timeout.

read -t 10

will do it

Solution 3:

Building on the thoughtful answers above, the return value from the read is useful to distinguish between an empty response from the user (for example "Press Enter" for the default action) and a timeout.

read -t 5 -p "Prompt " RESP
if [[ $? -gt 128 ]] ; then
    echo -e "\nTimeout"
else
    echo "Response = \"$RESP\""  # adding quotes so empty strings are obvious
fi

Another useful tidbit is that the -p "prompt " is written to stderr (not stdout) so if you're redirecting stderr, the prompt will not be displayed. An example of this would be logging an execution trace to a log file for later analysis. To use read -p Prompt in this case you can redirect stderr to the user for just the read statement.

set -x
exec 2>logfile
read -t 5 -p "Prompt " RESP 2>/dev/tty