我想从终端增量读取一行输入,并允许用户一些基本的行编辑功能; INS、DEL、右、左、结束、退格
每次修改字符串时,我都想对其进行处理,以对文本文件进行增量正则表达式搜索。
这些编辑键和其他键生成多个输入字符,这
使得解释输入变得相当困难,例如 C-Left 生成 6 个字符。
有没有一种简单的方法来实现这种逐字符可编辑输入?
我特别有兴趣知道如何在 bash 中执行此操作,因为其余的处理将是 bash.. 也欢迎其他建议..
这就是我开始的方式,但是对于如此多种潜在的控制代码,它有点失控。
#!/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
答案1
如果您使用 一次读取一个字符read -n
,则必须实现一个键序列解析器。您可以使用以下方法构建一个适用于大多数终端的缓慢而肮脏的解决方案:考虑功能键转义序列以转义字符开头,并以任意数量的字符继续,后面0-9;[]O
跟着一个不在此集合中的最后一个字符。
读取输入的更好方法是使用适当的输入库。 Bash 将其用于其自身目的(阅读线)。通过使用bind
内置声明您自己的键绑定,您可以获得有限的接口;专门bind -x
用于在按键时运行 shell 命令。由于接口有限,实现您想要的内容可能是可能的,但很困难。
Zsh有自己的输入库,兹勒。它的界面比 bash 丰富得多。使用 zle,您可以定义任意键盘映射,并且可以通过 shell 代码更好地访问 zle 的内部结构。用于zle
将 shell 函数分配给 zle 用户定义的命令(称为小部件),bindkey
创建并填充您自己的键盘映射,最后vared
使用您选择的键盘映射读取一行输入。
答案2
read
如果有字符,您可以在第一个终端之后将终端设置为原始模式esc
,然后使用第二个终端read
来读取和解析剩余的字节(如果有)(参见BASH逃避性格创伤另请参阅箭头.txt)。
#!/bin/bash
# tested on Mac OS X 10.6.8
IFS=$'\n'
old_tty_settings="$(stty -g)"
exec 0</dev/tty
tput smir # enable insert mode
while IFS="" read -r -s -n1 key; do # first read (reads only a single byte)
#od -c <<<"$key"
#continue
((${#key}==0)) && break
case "$key" in
$'\001') printf '\r' # ctrl-a
continue;;
$'\177') tput rmir
printf "\010\040\010\033[P" # backspace
tput smir
continue;;
$'\025') printf "\033[1K" # tput el1 does not work on Mac OS X 10.6.8
continue;; # ctrl-u (clear to start of line)
$'\v') tput el
continue;; # ctrl-k (clear to end of line)
esac
# if the first char is esc (i.e. \e or \033 respectively)
if [[ "$key" == $'\033' ]]; then
stty cbreak -echo min 0 time 0 # set raw terminal
IFS="" read -r bytes # second read (reads remaining bytes)
if [[ ${#bytes} -gt 0 ]]; then
stty "$old_tty_settings"
case "${key}${bytes}" in
$'\033[3~') tput dch1 # delete one char
continue;;
esac
printf "${key}${bytes}"
else
stty "$old_tty_settings"
fi
else
#stty "$old_tty_settings"
printf '%s' "$key"
fi
done
echo
exit 0
答案3
看一下命令行工具选择器。
# usage examples
selector -v -x @ <(find . -maxdepth 2 -type d | awk '{print $0"@cd "$0}')
selector -v -x @ <(grep -E -o 'http[^ ]+' fileWithURLS)
答案4
仅使用 bash 内置函数来不使用任何脚本:
read -e INPUT # single line
INPUT=$(</dev/stdin) # multiple lines
(来源)
或者,安装该ledit
软件包,然后您可以使用:
INPUT=$(ledit)