0

I'm in the process of creating a bash script. I need input from the user. Here's a snippet:

printf "Press$red Y$green to continue,$red N$green to Abort,$red D$green for Dry Run or$red H$green for Help\n\n" while [ true ]; do read -s -r -N 1 Selection case "$Selection" in y | Y) echo "Y was pressed";; n | N) echo "N was pressed";; d | D) echo "D was pressed";; h | H) echo "H was pressed";; esac 

This works as expected except the left arrow key responds as d. It seems to be the only key that puts in a false input.

How do I trap that?

0

2 Answers 2

1

Instead of read -s -r -N 1 use read -e -s -r -N 1 call. Here only addition is the -s switch which tells read to use readline library for input and then only read will be able to understand arrow keys and other complex keystrokes.

Sign up to request clarification or add additional context in comments.

Comments

1

The Root Cause: Arrow Keys Send Sequences

Here’s the deal: arrow keys aren’t “just a key.”
When you hit ←, you’re not sending one character — you’re sending a whole escape sequence.

For the usual arrows, it looks like this:

  • Left: ESC [ D

  • Right: ESC [ C

  • Up: ESC [ A

  • Down: ESC [ B

Now, your script is doing read -n1, which means “give me one char at a time.”
So when you press ←, this happens:

  1. First loop: it grabs ESC. Doesn’t match anything.

  2. Second loop: it grabs [. Still nothing.

  3. Third loop: it grabs D. Bingo, that matches your d|D case. Script goes “oh cool, D was pressed,” even though you just wanted to move left.

That’s why it looks like the left arrow is pretending to be d.

The Fix: Eat the Whole Sequence

You’ve got to trap that first ESC, and then slurp up the next couple of chars so they don’t pollute your logic. Here’s a clean way to do it:

printf "Press$red Y$green to continue,$red N$green to Abort,$red D$green for Dry Run or$red H$green for Help\n\n" while true; do # using -n instead of -N read -s -r -n 1 Selection case "$Selection" in y | Y) echo "Y was pressed";; n | N) echo "N was pressed";; d | D) echo "D was pressed";; h | H) echo "H was pressed";; $'\e') # Arrow keys start with ESC, so grab the rest read -s -r -n 2 -t 0.1 rest;; # Do nothing — just flush it esac done 

$'\e' catches the start of any funky key (arrows, F-keys, etc)

read -n2 -t0.1 slurps up the [D part so it doesn’t leak into your loop

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.