24

I need to compare my input with Enter/Return key...

read -n1 key
if [ $key == "\n" ]
   echo "@@@"
fi

But this is not working.. What is wrong with this code

Martin Zeitler
  • 1
  • 19
  • 155
  • 216
veda
  • 6,416
  • 15
  • 58
  • 78
  • 1
    You're missing "then" on the line between "if" and "echo". Not the only problem, but one – Phil Apr 10 '10 at 04:56

5 Answers5

41

Several issues with the posted code. Inline comments detail what to fix:

#!/bin/bash 
# ^^ Bash, not sh, must be used for read options

read -s -n 1 key  # -s: do not echo input character. -n 1: read only 1 character (separate with space)

# double brackets to test, single equals sign, empty string for just 'enter' in this case...
# if [[ ... ]] is followed by semicolon and 'then' keyword
if [[ $key = "" ]]; then 
    echo 'You pressed enter!'
else
    echo "You pressed '$key'"
fi
Mark Rushakoff
  • 249,864
  • 45
  • 407
  • 398
  • 9
    This doesn't work. If you press ESC it goes to "You presesed enter!" – Bruno Medina May 11 '18 at 17:37
  • @Jiu, seems that you're using `sh file` to execute it rather than `bash file` or just `./file` if it has `chmod +x file`. I would remark that Googling is far away faster than wrote such comment. – m3nda Mar 19 '19 at 11:38
  • 1
    @BrunoMedina. Well, if you use raw option `-r` you'll read `""` for Return key and `"\e"` for escape key, making a difference between them. Using the current `read -s -n` will strip out backslashed's, making both as `""`. So, just `read -r -s -n 1 key` will solve. – m3nda Mar 19 '19 at 11:44
8

Also it is good idea to define empty $IFS (internal field separator) before making comparisons, because otherwise you can end up with " " and "\n" being equal.

So the code should look like this:

# for distinguishing " ", "\t" from "\n"
IFS=

read -n 1 key
if [ "$key" = "" ]; then
   echo "This was really Enter, not space, tab or something else"
fi
tsds
  • 8,700
  • 12
  • 62
  • 83
  • #this does not work for me if using loop printing coutdown IFS= echo -e "Press [ENTER] For Keyboard Configuration." for (( i=10; i>0; i--)); do printf "\rStarting in $i seconds..." read -n 1 -t 1 key if [ "$key" = $'\e' ]; then echo "This is ESC" break elif [ "$key" == "" ] ;then echo -e "\n space is pressed" break fi done – Asaf Magen Apr 25 '16 at 13:34
  • 1
    maybe the thing is that for inline syntax you should use IFS=; echo... (with semicolon) – tsds Apr 25 '16 at 14:39
  • 2
    Pretty nice fix just using `IFS=` – m3nda Mar 19 '19 at 11:48
  • Doesn't this change the behavior of the rest of the script? – vhs Mar 16 '22 at 16:02
6

I'm adding below code just for reference if someone will want to use such solution containing countdown loop.

IFS=''
echo -e "Press [ENTER] to start Configuration..."
for (( i=10; i>0; i--)); do

printf "\rStarting in $i seconds..."
read -s -N 1 -t 1 key

if [ "$key" = $'\e' ]; then
        echo -e "\n [ESC] Pressed"
        break
elif [ "$key" == $'\x0a' ] ;then
        echo -e "\n [Enter] Pressed"
        break
fi

done
Asaf Magen
  • 862
  • 10
  • 22
4

read reads a line from standard input, up to but not including the new line at the end of the line. -n specifies the maximum number of characters, forcing read to return early if you reach that number of characters. It will still end earlier however, when the Return key is pressed. In this case, its returning an empty string - everything up to but not including the Return key.

You need to compare against the empty string to tell if the user immediately pressed Return.

read -n1 KEY
if [[ "$KEY" == "" ]]
then
  echo "@@@";
fi
udondan
  • 57,263
  • 20
  • 190
  • 175
user229044
  • 232,980
  • 40
  • 330
  • 338
2

None of these conditions worked for me and so I've came up with this one:

${key} = $'\0A'

Tested on CentOS with Bash 4.2.46.

Martin Zeitler
  • 1
  • 19
  • 155
  • 216