Bash script listen for key press to move on

kev's great solution works well even in Bash 3.x., but it introduces a 1-second delay (-t 1) in every loop iteration.

In Bash 3.x, the lowest supported value for -t (timeout) is 1 (second), unfortunately.

Bash 4.x supports 0 and fractional values, however:

A solution that supports an arbitrary key such as q requires a nonzero -t value, but you can specify a value very close to 0 to minimize the delay:

#!/bin/bash
# !! BASH 4.x+ ONLY

while :; do

  # Loop command
  date

  # Check for 'q' keypress *waiting very briefly*  and exit the loop, if found.
  read -t 0.01 -r -s -N 1 && [[ $REPLY == 'q' ]] && break

done

# Post-loop command
date +%s

Caveat: The above uses 0.01 as the almost-no-timeout value, but, depending on your host platform, terminal program and possibly CPU speed/configuration, a larger value may be required / a smaller value may be supported. If the value is too small, you'll see intermittent error setting terminal attributes: Interrupted system call errors - if anyone knows why, do tell us.


Tip of the hat to jarno for his help with the following:

Using -t 0, works as follows, according to help read (emphasis added):

If TIMEOUT is 0, read returns immediately, without trying to read any data, returning success only if input is available on the specified file descriptor.

As of Bash v4.4.12 and 5.0.11, unfortunately, -t 0 seems to ignore -n / -N, so that only an ENTER keypress (or a sequence of keypresses ending in ENTER) causes read to indicate that data is available.
If anyone knows whether this is a bug or whether there's a good reason for this behavior, do let us know.

Therefore, only with ENTER as the quit key is a -t 0 solution currently possible:

#!/bin/bash
# !! BASH 4.x+ ONLY

while :; do

  # Loop command
  date

  # Check for ENTER keypress and, after clearing the input buffer
  # with a dummy `read`, exit the loop.
  read -t 0 -r -N 1 && { read -r; break; }

done

# Post-loop command
date +%s

you can use read builtin command with option -t and -n

while :
do
    # TASK 1
    date
    read -t 1 -n 1 key

    if [[ $key = q ]]
    then
        break
    fi
done

# TASK 2
date +%s

Tags:

Shell

Bash