Processing User Input: Timeout Mechanisms
Ed Schaefer and John Spurgeon
Waiting for a user to respond to a program that is
requesting input can be an issue. How do you provide a timeout mechanism in
your shell scripts? In this column, we consider three methods. We touch on
the read command's -t option; we discuss manipulating the terminal driver with the stty command; and we
present our own script, called timeout_countdown, that can kill another
process if the user doesn't respond within a certain amount of time.
Using the read Command
The bash and ksh93 shells provide a timeout option for
the read command.
The following stub waits 5 seconds before exiting the script:
any_key=""
echo "wait 5 seconds for input"
read -t5 any_key
if [[ -z "$any_key" ]]
then
echo "User neglected to enter value
within 5 seconds"
exit 1
fi
echo "any_key is: $any_key"
Manipulating the Terminal
If you're using the Bourne shell or ksh88, the comp.unix.shell FAQ provides a solution that manipulates the
terminal driver. In a sub-process, save the terminal mode, using the stty command, turn off
canonical processing and wait. Then, grab one line of input and restore the
saved terminal settings:
#!/bin/ksh
any_key=""
echo "wait 5 seconds for input"
{
oldtty=$(stty -g)
stty -icanon min 0 time 50
any_key=$(head -n 1)
stty "$oldtty"
}
if [[ -z $any_key ]]
then
echo "User neglected to enter value within 5 seconds"
exit 1
fi
echo "any_key: is $any_key"
While this solution is elegant, it does not handle
special characters well. Since canonical mode is off, the special
characters are processed as individual keystrokes. For example, the back
space key doesn't function as a back space, and the interrupt key
-- after waiting the prescribed time out -- terminates the parent
shell. This logs you out if the parent shell was your original login shell.
You can always turn off signals by changing the stty command, which disables processing special characters:
stty -icanon min 0 time 50 -isig
Using the timeout_countdown Script
For cases where the read command's -t option isn't supported, we developed the
timeout_countdown script (Listing 1). Before
executing a command that prompts the user for input, start the
timeout_countdown script in the background. If the user doesn't enter
input within the required timeframe, then the timeout_countdown kills its
parent or possibly some other specified process. If the user enters input
within the timeframe, another call to timeout_countdown with the stop
argument prevents the process from being killed; it's like disabling
a time bomb. The following script demonstrates the use of timeout_countdown:
#!/bin/ksh
# timeout.ss: timeout_countdown demo
echo "Enter input within 5 seconds or else!"
timeout_countdown -t 5 start &
read any_key
timeout_countdown stop
echo "any_key is: $any_key"
# end script
With the start argument, timeout_countdown by default
finds the parent process id with the ps -p command and saves its own process id in a temporary
file. If the user doesn't respond, the script sleeps for the
specified amount of time (5 seconds in this case), kills the timeout.ss
process, and deletes the temporary file.
If the user responds to the read command's
prompt before the timeout period, then timeout_countdown is executed again
with the stop argument. Calling timeout_countdown with the stop argument
retrieves the process id of the initial timeout_countdown process and kills
it, thus preventing timeout.ss from being killed.
When called with the stop argument, the
timeout_countdown script performs a sanity check before killing a process
(viz., before disabling the corresponding timeout_countdown time bomb). The
script uses the process id to retrieve the name of the command it's
about to kill and verifies that it appears to be an instance of a
timeout_countdown process.
The -t option changes the 300 second default time frame, and the -d option changes the default
/tmp temporary file directory. Finally, by default, timeout_countdown
determines its parent's process id. You can overrule the default by
passing another process id with the -p option.
Resource
Comp.unix.shell newsgroup FAQ, Part 2 -- http://home.comcast.net/~j.p.h/cus-faq-2
John Spurgeon is a software developer and systems
administrator for Intel's Factory Information Control Systems, IFICS,
in Aloha, Oregon. Outside of work, he enjoys turfgrass management,
triathlons, ultra-marathon cycling, and spending time with his family.
Ed Schaefer is a frequent contributor to Sys Admin. He is a software
developer and DBA for Intel's Factory Information Control Systems,
IFICS, in Aloha, Oregon. Ed also hosts the monthly Shell Corner column on
UnixReview.com. He can be reached at: shellcorner@comcast.net.
|