BASH - Read - How to require [enter] to complete input? Example [y] + [enter]

43 Views Asked by At

I haven't been able to find an answer to this online, or in the read manual.

I have a simple Yes / No prompt, that accepts y or n.

I'm trying to have it require enter (specifically) to be pressed, after typing y, or n.

Example:

$ Do you want to continue?

_ y + enter

$ Continuing!

Below is the code I have currently:

while true; do
    read -n 1 -r -p "Continue (y/n):" yn

        case $yn in 
            [yY] ) 
                echo "Yes - Continuing..."
                break;;
            [nN] )
                echo "No - Exiting..."
                exit;;
            * ) 
                echo "Invalid response!";;
    esac
done

I've tried setting -n 2 which "sort of" works, as it requires 2 keys to be pressed, however, if I type y, then change my mind and hit backspace, it will sill proceed and continue. Same thing if I "fat finger" things... like bn or ty will continue, since there's an n or a y in the response.

How can I require 2 keys to be pressed, one being y or Y and the enter key specifically, ignoring any other combination?

[Edit]

Setting -n 2 and requiring [yY]'' ) seems to work, but it still falls back to "Invalid Input" if I try y + backspace.

Not sure how I can ignore the backspace key being counted as an "input".

1

There are 1 best solutions below

0
Ed Morton On

If, as is common on PC keyboards, when you hit the Backspace key on your keyboard it generates the Del character (ASCII dec 127, hex 177, Control-?), rather than the backspace character (ASCII 8, Control-H), then all you need is:

$ cat tst.sh
#!/usr/bin/env bash

while true; do
    IFS= read -r -p 'Continue (y/n): ' yn

    case $yn in
        [yY] )
            echo 'Yes - Continuing...'
            break;;
        [nN] )
            echo 'No - Exiting...'
            exit;;
        * )
            echo 'Invalid response!';;
    esac

done

because the read will complete when you hit Enter to generate a newline, then the case will check for the 1 char before that newline being y or n.

Unless you put your terminal into "raw" mode your terminal buffers the keypresses until you hit Enter so the terminal, not your script, is what interprets that backspace keypress and deletes the preceding character from the input buffer before your script sees it. So if you type n backspace y your script will just read y, same as if you hadn't hit n backspace first. See https://unix.stackexchange.com/a/414171/133219 for more information.

Unfortunately the whole "Backspace" vs "Delete" area is a bit of a mess with Macs having a Delete key generating the Del character where the PC Backspace key is that generates Del character on some OSes and the BS character on others, and then Macs not having a Backspace key but instead requiring key combinations to generate BS, and PCs having a Delete key that generates something that isn't an ASCII character, etc. hence the "If your keyboard generates Del when Backspace is hit" caveat at the top of this answer.