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:
First loop: it grabs ESC. Doesn’t match anything.
Second loop: it grabs [. Still nothing.
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