0

I have the following piece of code that will allow me to type any letter or number:

#!/bin/bash

while IFS= read -s -n1 char; do
  if ! [[ $char =~ [A-Za-z0-9]+$ ]]; then break; fi
  value+=$char
  echo -n "*"
done

echo
echo "val = $value"

What I would like to do, however, is allow for the backspace, delete and arrow keys to perform like normal without causing the script to abort. I'm assuming I need to capture some form of ANSI equivalent and just have a different operation if that key is used. But I'm not sure how to do that...

user3299633
  • 2,971
  • 3
  • 24
  • 38
  • 2
    You can't while reading only one character at a time. For example, an arrow key actually generates a terminal-dependent sequence of characters (almost always more than one), so your `read` command will only get the first one. You can use `read -s -e value` to let the user use the full power of `Readline` to edit the password, but then you can't show progress. You need something more powerful than `read` alone (such as the `curses` library) to do this type of interface. – chepner Aug 31 '16 at 21:16
  • The backspace is doable if you can trap char `0x08` and then use something like `stty erase` to backup, but the arrow keys are multi-byte chars as explained above. You can either use a curses lib, or you can write a short input handler that puts the keyboard (terminal) in raw-unbuffered mode that will allow reading *key-presses*, but that requires something other than shell scripting. – David C. Rankin Aug 31 '16 at 21:57
  • The marked duplicate has a couple of answers which outline how to handle terminal control input. They handle backspace, but should be possible to extend to multi-character sequences with a simpole state machine. (I.e. if the current character is esc, set a flag and loop; now, on the next iteration, take a different branch to a different `case` statement if the `esc_state` flag is true.) – tripleee Sep 01 '16 at 04:19

0 Answers0