Bash – Reading and Processing Strings Character by Character

bashterminaltext processing

I want to incrementally read a line of input from the terminal,
and allow the user some basic line editing functionality; INS, DEL, RIGHT, LEFT HOME, END, BACKSPACE

Each time the string is modified, I want to process it, to do an incremental regex search of a text file.

These edit-keys, and others, generate multiple input characters which
make it rather difficult to interpret the input, eg C-Left generates 6 characters.

Is there a simple way to achieve this char-by-char editable input?
I'm especialy interested in knowing how to do this in bash, because the rest of the processing will be bash..
Other suggestions are welcome too..

Here is how I started out, but it gets a bit out of hand with such a potential variety of control codes ..

#!/bin/bash
IFS=$'\n' 
while true ;do
  read -n 1 c
  ((${#c}==0)) && break # Exit the loop. Input length is 0  
                        # ie. The user has pressed Enter
  echo "xx=$(echo -n "$c"|xxd -p)="
  # 1b 5b 32 7e  "INS"
  # 1b 5b 33 7e  "DEL"
  # 1b 5b 43     "RIGHT"
  # 1b 5b 44     "LEFT"
  # 1b 5b 46     "END"
  # 1b 5b 48     "HOME"
  # 7f           "BACKSPACE"
done

Best Answer

If you read a character at a time with read -n, you'll have to implement a key sequence parser. You can build a slow-and-dirty solution that works on most terminals with this: consider that a function key escape sequence begins with an escape character and continues with any number of characters amongst 0-9;[]O followed by one final character not in this set.

A better way to read input is to use a proper input library. Bash uses one for its own purposes (readline). You get a limited interface to it by declaring your own keybindings with the bind built-in; specifically bind -x to run a shell command on a key press. Because of this limited interface, implementing what you want is likely to be possible but difficult.

Zsh has its own input library, zle. Its interface is a lot richer than bash's. With zle, you can define arbitrary keymaps, and you get more access to the internals of zle from shell code. Use zle to assign shell functions to zle user-defined commands (called widgets), bindkey to create and populate your own keymap, and finally vared to read a line of input using the keymap of your choice.

Related Question