|
|
read reads a line of text at a time, but it is often useful to have a script wait for a keystroke, then act on that keystroke immediately. For example, when using a menu driven program, you may not want the program to wait for you to press <Enter> after you select an item. There is no command to obtain a single character from a terminal, but we can simulate one.
Here is a simple function to obtain a keystroke:
getc ()
{
stty raw
tmp=`dd bs=1 count=1 2>/dev/null`
eval $1='$tmp'
stty cooked
}
To use it, insert it at the top of your shell script, then invoke it
lower down the shell script:
echo "Enter a character: \c" getc char echo echo "You entered $char"getc puts the terminal into raw mode. Instead of passing your input through to the system a line at a time, the terminal now passes each keystroke you type straight through, unmodified.
The dd command reads a single character from the standard input and writes it to the standard output, that is captured in the variable tmp. The next line is used to assign the literal contents of tmp to the variable named by $1. The eval command in front of this line is necessary to force the shell to scan the line twice; once to expand $1 into the name of a variable, and again to carry out the actual command. The quotes around $tmp are stripped off by eval; if you omit them, then if your character is a whitespace character, it will be lost.
Afterwards, getc puts the terminal back into normal operating mode with the command stty cooked (or stty -raw, or stty sane).
We can write getc more succinctly like this:
getc ()
{
stty raw
eval $1=´`dd bs=1 count=1 2>/dev/null`´
stty cooked
}
Because getc returns a single character in whatever
variable you specify, you can use it flexibly. For example, the
following function can be used to make a program pause until you are
ready for it to continue:
press_any_key()
{
echo "Strike any key to continue ...\c"
getc anychar
}
Combine the two functions in a script called char_handler,
as follows:
getc ()
{
stty raw
eval $1=´`dd bs=1 count=1 2>/dev/null`´
stty cooked
}
press_any_key()
{
echo "Strike any key to continue ...\c"
getc anychar
}
echo "Enter a character: \c"
getc char
echo
echo "You entered $char"
press_any_key char
echo \r
Execute char_handler as follows:
$./char_handlerEnter a character:xYou entered x Strike any key to continue ...y$