7

Hi I'm trying to implement an event that will happen after a 5 second countdown, unless a key is pressed. I have been using this code, but it fails if I press enter or space. It fails in the sense that enter or space is detected as "".

echo "Phoning home..."
key=""
read -r -s -n 1 -t 5 -p "Press any key to abort in the next 5 seconds." key
echo
if [ "$key" = "" ]     # No Keypress detected, phone home.
     then python /home/myuser/bin/phonehome.py
     else echo "Aborting."
fi

After reading this post, Bash: Check if enter was pressed

I gave up and posted here. I feel like there must be a better way than what I have tried to implement.

Community
  • 1
  • 1
inkman
  • 71
  • 3

2 Answers2

4

The read manual says:

The return code for read is zero, unless end-of-file is encountered or read times out.

In your case, when the user hits any key within allowed time you wish to abort else continue.

#!/bin/bash
if read -r -s -n 1 -t 5 -p "TEST:" key #key in a sense has no use at all
then
    echo "aborted"
else
    echo "continued"
fi

Reference: Read Manual
Note: The emphasis in the citation is mine.

sjsam
  • 21,411
  • 5
  • 55
  • 102
  • This way seemed most elegant and this is the way I ended up doing this. Thanks very much for the response. – inkman Dec 25 '15 at 00:28
2

The accepted answer in the linked question covers the "detecting enter" component of the question. You look at the exit code from read.

As to handling spaces there are two answers.

The problem with space is that under normal circumstances read trims leading and trailing whitespace from the input (and word-splits the input) when assigning the input to the given variables.

There are two ways to avoid that.

  1. You can avoid using a custom named variable and use $REPLY instead. When assigning to $REPLY no whitespace trimming or word-splitting is performed. (Though looking for this just now I can't actually find this in the POSIX spec so this may be a non-standard and/or non-portable expansion of some sort.)

  2. Explicitly set IFS to an empty string for the read command so it doesn't perform and whitespace trimming or word-splitting.

    $ IFS= read -r -s -n 1 -t 5 -p "Press any key to abort in the next 5 seconds." key; echo $?
    # Press <space>
    0
    $ declare -p key
    declare -- k=" "
    $ unset -v k
    $ IFS= read -r -s -n 1 -t 5 -p "Press any key to abort in the next 5 seconds." key; echo $?
    # Wait
    1
    $ declare -p key
    -bash: declare: k: not found
    
Community
  • 1
  • 1
Etan Reisner
  • 77,877
  • 8
  • 106
  • 148