How to use Bash read with a timeout?

I can ask the user to press Enter by using read, and have him wait by calling sleep. But I can’t think of a way of doing both at the same time. I would like the user to be given the choice:

Press Ctrl+C to Cancel, Enter to continue or just wait 10 seconds

How can I do that?

57890 次浏览

The read builtin has a timeout.

read -t 10

will do it

In bash(1), 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

(1) If you're doing this in a script, make sure that it's a bash one. You can do that by adding a shebang line at the start such as one of the following:

#!/usr/bin/env bash
#!/bin/bash

From the bash reference manual :

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

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