1833994 Members
5725 Online
110063 Solutions
New Discussion

scripts problem

 
SOLVED
Go to solution
Maxim Rozin
Frequent Advisor

scripts problem

i am writing a shell script and i want to read a character from the standart input and put it in a varaible without the need of ënter" or newline.

if some one knows how to do it it will be great

thanx.
8 REPLIES 8
Mark Grant
Honored Contributor

Re: scripts problem

Can't be done. Sorry.

There are no shell tools for this. I once wrote a little C program which did this and returned the ascii value of the character pressed but can't find it :(

You can do it in C and set the terminal to raw mode and a few other bits and bobs. If you want to do it the simple way, a small C program that uses "curses". Curses has a function to achieve this for you.
Never preceed any demonstration with anything more predictive than "watch this"
A. Clay Stephenson
Acclaimed Contributor
Solution

Re: scripts problem

My preferred way to do this is a small C program because it guarantees that you will reset the terminal and will automatically fold upper to lower case (or vice-versa), if desired:


e.g.
CH=$(onechar -L)
STAT=${?}
case ${STAT} in
0) echo "You pressed ${CH}"
;;
255) echo "This is an error" >&2
;;
*) echo "The ASCII value pressed is \c"
echo "${STAT} (dec)"
;;
esac

The idea is if 0 is returned, a printable character is output on stdout, a return of 255 indicates an error, any other returns indicates that a non-pritable ASCII character was received and the return value is the decimal equivalent and no character is output to stdout.

If you need to recognize function keys or arrow-keys then you really need to use curses. Man curses for details.


This is onechar.c. Compile it like this:
cc onechar.c -o onechar

If it ain't broke, I can fix that.
A. Clay Stephenson
Acclaimed Contributor

Re: scripts problem


Here is a pure shell method but I consider it much less robust:

#!/usr/bin/sh

echo "Enter character: \c"
stty raw
CH=$(dd if=/dev/tty bs=1 count=1 2>/dev/null)
stty -raw
echo "You entered ${CH}"

The reason this is not so nice is that no mechanism is present to easily recognize non-ASCII characters. Whatever you do, make sure that the second stty gets called because terminal settings affect not just the process but ALL processes for which this terminal is the controlling terminal.

The C program makes certain that this is done and easily tells you when a control character was entered.

If it ain't broke, I can fix that.
Maxim Rozin
Frequent Advisor

Re: scripts problem

thanx,

but i cannot see the c program
Bill Hassell
Honored Contributor

Re: scripts problem

No problem. Here is a function that will work in POSIX or Korn shell:

###########################################
function GetChar1
{

# Read 1 character and return as first argument
# example: GetChar1 MYCHAR

stty raw
eval $1='"$(dd bs=1 count=1 2>/dev/null)"'
stty cooked
}

Just call this when you need one character.


Bill Hassell, sysadmin
A. Clay Stephenson
Acclaimed Contributor

Re: scripts problem

The C source, onechar.c, is an attachment to my first posting.
If it ain't broke, I can fix that.
Mark Grant
Honored Contributor

Re: scripts problem

Well guys, I'm impressed.

I just sat here and re-coded a raw mode getc and found A.Clay got in there well before hand and then Bill comes along with a cute Korn version.

I'll get my coat :)
Never preceed any demonstration with anything more predictive than "watch this"
Bill Hassell
Honored Contributor

Re: scripts problem

To amplify a bit on the shell method, I assume that a monkey is typing so every character is possible. That makes shell comparisons a bit tricky so I convert the character to hex and compare for things like control characters something like this:

GetChar1 "MYCHAR"

# Search for an acceptable response. Since just CR
# (or other control chars) might be entered, convert
# MYCHAR to hex and test accordingly.

HEX=$(echo "$MYCHAR" \
| xd \
| head -1 \
| awk '{print $2}' \
| cut -c 1-2)

# CR or CTRL-D? Bail out.

if [ "$HEX" = "0d" -o "$HEX" = "04" ]
then
echo "\n\n"
exit

...and so on...


Bill Hassell, sysadmin