Bash KeyPress (or Read Single Character)


Login or Register to Reply

 
Thread Tools Search this Thread
# 1  
Bash KeyPress (or Read Single Character)

Hi,

I'm sorry if this has already been posted somewhere but I can't seem to find it on the forums (or anywhere on google Smilie )

I am writing a script where a user must enter a single character to perform an action.

For example, Press Q to Quit or R to Refresh

Basically I am stuggling to come up with a way you can use the read function to read one character (without pressing enter or return) and then perform a command based on what character you entered.

The only solution I can find is read -n but this isn't available for me.

I've used the following code to perform a timed out read which will wait 1 second and then continue the code but it takes too long.

Code:
timedout_read() {
  timeout=$1
  varname=$2
  old_tty_settings=`stty -g`
  stty -icanon min 0 time ${timeout}0
  eval read $varname
  stty "$old_tty_settings"
}

timedout_read 1 TEST

Does anyone have any idea how to read single character without having to press enter?
# 2  
I've found this piece of code in the past, it works with bash. Play around with it:
Code:
#!/bin/bash
 
_key()
{
  local kp
  ESC=$'\e'
  _KEY=
  read -d '' -sn1 _KEY
  case $_KEY in
    "$ESC")
        while read -d '' -sn1 -t1 kp
        do
          _KEY=$_KEY$kp
          case $kp in
            [a-zA-NP-Z~]) break;;
          esac
        done
    ;;
  esac
  printf -v "${1:-_KEY}" "%s" "$_KEY"
}
 
_key x
 

case $x in
  $'\e[11~' | $'\e[OP') key=F1 ;;
  $'\e[12~' | $'\e[OQ') key=F2 ;;
  $'\e[13~' | $'\e[OR') key=F3 ;;
  $'\e[14~' | $'\e[OS') key=F4 ;;
  $'\e[15~') key=F5 ;;
  $'\e[16~') key=F6 ;;
  $'\e[17~') key=F7 ;;
  $'\e[18~') key=F8 ;;
  $'\e[19~') key=F9 ;;
  $'\e[20~') key=F10 ;;
  $'\e[21~') key=F11 ;;
  $'\e[22~') key=F12 ;;
  $'\e[A' ) key=UP ;;
  $'\e[B' ) key=DOWN ;;
  $'\e[C' ) key=RIGHT ;;
  $'\e[D' ) key=LEFT ;;
  ?) key=$x ;;
  *) key=??? ;;
esac
 
echo "You have pressed $key"

# 3  
try
Code:
echo -n "Enter character: "
stty cbreak
char=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
stty -cbreak
echo " Character was: $char"

# 4  
Thanks for the quick replies

Franklin52
When I try your method I get the following errors
Code:
./test.sh: read: illegal option: -d
read: usage: read [-r] [-p prompt] [-a array] [-e] [name ...]
./test.sh: printf: illegal option: -v
printf: usage: printf format [arguments]
You have pressed ???

funksen
When I try your method I get the following errors
Code:
unknown mode: cbreak
^[[B
unknown mode: -cbreak

It appears that I don't have the read -d, printf -v and cbreak functions.

Do you know of any other ways to do this?
# 5  
try -icanon instead of -cbreak, if this doesn't work, use -raw

Edit: tried on AIX, raw worked
# 6  
Thanks Funksen, raw works for me too!

---------- Post updated at 01:31 PM ---------- Previous update was at 12:54 PM ----------

Sorry to bother you again.

When I tried this previously, I just had a standard read command.
So I would press the key and then press return and the command would be fired.

Now that have the below code instead, I can't seem to capture the keypresses correctly
Code:
	stty raw
	sel=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
	stty -raw

I used to have
Code:
read sel

case $sel in
		1)  KEY=1 ; NUM=$sel
	;;
		2)  KEY=2 ; NUM=$sel
	;;
		3)  KEY=3 ; NUM=$sel
	;;
		4)  KEY=4 ; NUM=$sel
	;;
		5)  KEY=5 ; NUM=$sel
	;;
		6)  KEY="" ; QUIT="Y" 
	;;
		["Q","q"]) KEY="" ; QUIT="Y" 
	;;
		$'\e[A' ) 
		if [ $NUM -eq 1 ]
		then
			NUM=6
		else
			NUM=$(($NUM - 1)) 
		fi
	;;
		$'\e[B' ) 
		if [ $NUM -eq 6 ]
		then
			NUM=1
		else
			NUM=$(($NUM + 1)) 
		fi
	;;
		"") KEY=$NUM 
	;;
		*) echo "ERROR"
	;;
	esac

This would determine whether the user was pressing up and down, q, a number or just pressing enter.

Now when I use the same code it isn't recognising the up, down or enter keypresses.

Have you any idea what I should change to get it to work.

Just to clarify, my code looks like the following.
Code:
	echo -n "Choose one: " 
	stty raw
	sel=`dd if=/dev/tty bs=1 count=1 2>/dev/null`
	stty -raw
		
	case $sel in
		1)  KEY=1 ; NUM=$sel
	;;
		2)  KEY=2 ; NUM=$sel
	;;
		3)  KEY=3 ; NUM=$sel
	;;
		4)  KEY=4 ; NUM=$sel
	;;
		5)  KEY=5 ; NUM=$sel
	;;
		6)  KEY="" ; QUIT="Y" 
	;;
		["Q","q"]) KEY="" ; QUIT="Y" 
	;;
		$'\e[A' ) 
		if [ $NUM -eq 1 ]
		then
			NUM=6
		else
			NUM=$(($NUM - 1)) 
		fi
	;;
		$'\e[B' ) 
		if [ $NUM -eq 6 ]
		then
			NUM=1
		else
			NUM=$(($NUM + 1)) 
		fi
	;;
		"") KEY=$NUM 
	;;
		*) echo "ERROR"
	;;
	esac

Any suggestions would be much appreciated.
Login or Register to Reply

|
Thread Tools Search this Thread
Search this Thread:
Advanced Search

More UNIX and Linux Forum Topics You Might Find Helpful
How to repeat a character in a field if it's a single character?
nengcheng
I have a csv dataset like this : C,rs18768 G,rs13785 GA,rs1065 G,rs1801279 T,rs9274407 A,rs730012 I'm thinking of use like awk, sed to covert the dataset to this format: (if it's two character, then keep the same) CC,rs18768 GG,rs13785 GA,rs1065 GG,rs1801279 TT,rs9274407...... Shell Programming and Scripting
7
Shell Programming and Scripting
Simulate keypress in bash
supernono06
Hello everybody, I am using Windows 10 and cygwin/bash. I need to write a script in bash which simulates opening of a program and then press some keys such as F5, ENTER and ALT+F4. I have written a VBScript which does the job Set WshShell = WScript.CreateObject("WScript.Shell")...... UNIX for Beginners Questions & Answers
9
UNIX for Beginners Questions & Answers
Bash loop hording keypress input
DarkPhoenix
I have a bash loop that waits for a single key press, then does $something depending on what $key is pressed before refreshing the screen with updated data. The problem I have is that the script will store additional key presses and chain them together causing the screen to redraw and the script...... Shell Programming and Scripting
1
Shell Programming and Scripting
Replace multiple occurances of same character with a single character.
dipanchandra
Hi all, Greetings, I have the following scenario, The contents of main file are like : Unix|||||forum|||||||||||||||is||||||the||best so||||||be|||||on||||||||||||||||||||||||||||||||||||||||||||it And i need the output in the following form: Unix=forum=is=the=best so=be=on=it ...... Shell Programming and Scripting
3
Shell Programming and Scripting
bash while read how to remove \n character
papasj
Hi, I've made a script to grep a file for i in `cat filename.txt` do strings ./binfile | grep "$i" 2>&1 > /dev/null done this works fine as long as in filename.txt i don't have any entries with spaces. But in my case i want to grep something with spaces like "lala tata" and...... Shell Programming and Scripting
3
Shell Programming and Scripting