Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash script listen for key press to move on

Tags:

bash

shell

So, I want to write a bash script that are a sequence of steps and ill identify it as "task#". However, each step is only completed and can run as long as the user wants.

Do task1
if keypressed stop task1 and move on #this is the part I need help with. There can be up to 10 of these move on steps. 
Do task2
...

kina like top; it keeps doing stuff until you hit q to quite, however, i want to move on to the next thing

like image 691
Cripto Avatar asked Mar 16 '12 03:03

Cripto


2 Answers

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
like image 57
kev Avatar answered Sep 30 '22 07:09

kev


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
like image 43
mklement0 Avatar answered Sep 30 '22 07:09

mklement0