DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
Automating frequent tasks

Reading a single character from a file or a terminal

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_handler
   Enter a character: x
   You entered x
   Strike any key to continue ...y
   $

Next topic: Attaching a file to a file descriptor
Previous topic: Getting input from a file or a terminal

© 2003 Caldera International, Inc. All rights reserved.
SCO OpenServer Release 5.0.7 -- 11 February 2003