终端驱动程序在大多数系统上都具有行编辑功能。您会注意到有时可以使用Backspace, Ctrl-U, Ctrl-W。
readline
是一个 GNU 库,与bash
. 没有任何关于它的 POSIX。POSIX 为 定义了一个可选的行编辑器(带vi
键绑定)sh
,但没有规定在sh
.
当 stdin 和 stderr 都是终端并且相应的选项已经设置时,ksh93
shell 使用该vi
-style 行编辑器(也支持emacs
或gmacs
-style)作为其read
内置:set -o emacs; IFS= read -r var
例如read
使用 emacs 样式的行编辑器。
POSIX 确实指定了vi
编辑器(可选),因此您可以调用vi
以编辑临时文件的内容。
's的zsh
等价物是(更高级,因为它使用's zle(zsh 行编辑器))。bash
read -e
vared
zsh
在其他 shell 中,您可以在 readline 或其他行编辑库(如rlwrap
)周围使用一些包装器,或者您可以调用bash -c 'read -e...'
或zsh -c 'vared...'
。
您还可以做的是让用户有机会启动编辑器。
喜欢:
if ! IFS= read -r var; then
if [ -n "$var" ]; then
tmp=$(create_tempfile) # create_tempfile left as an exercise
printf '%s\n' "$var" > "$tmp"
"${VISUAL:-${EDITOR:-vi}}" -- "$tmp"
var=$(cat < "$tmp")
rm -f -- "$tmp"
else
exit 1 # real EOF?
fi
fi
Run Code Online (Sandbox Code Playgroud)
然后用户可以按Ctrl-D两次以在他已经输入的内容上启动编辑器。
否则,我曾经编写过该函数,该函数应该适用于大多数实现简单行编辑器的 Unices 上的大多数终端。
LE() {
# shell Line Editor. Extremely slow and stupid code. However it
# should work on ansi/vt100/linux derived terminals on POSIX
# systems.
# Understands some emacs key bindings: CTRL-(A,B,D,E,F,H,K,L)
# plus the CTRL-W and CTRL-U normal killword and kill.
# no Meta-X key, but handling of <Left>, <Right>, <Home>, <End>
# <Suppr>.
#
# Args:
# [1]: prompt (\x sequences recognized, defaults to "")
# [2]: max input length (unlimited if < 0, (default))
# [3]: fill character when erasing (defaults to space)
# [4]: initial value.
# Returns:
# 0: OK
# 1: od(d) error or CTRL-C hit
LE_prompt=$1
LE_max=${2--1}
LE_fill=${3-" "}
LE_backward() {
LE_s=$1
while [ "x$LE_s" != x ]; do
printf '\b%s' "$2"
LE_s=${LE_s%?}
done
}
LE_fill() {
LE_s=$1
while [ "x$LE_s" != x ]; do
printf %s "$LE_fill"
LE_s=${LE_s%?}
done
}
LE_restore='stty "$LE_tty"
LC_COLLATE='${LC_COLLATE-"; unset LC_COLLATE"}
LE_ret=1 LE_tty=$(stty -g) LE_px=$4 LE_sx= LC_COLLATE=C
stty -icanon -echo -isig min 100 time 1 -istrip
printf '%b%s' "$LE_prompt" "$LE_px"
while set -- $(dd bs=100 count=1 2> /dev/null | od -vAn -to1); do
while [ "$#" -gt 0 ]; do
LE_k=$1
shift
if [ "$LE_k" = 033 ]; then
case "$1$2$3" in
133103*|117103*) shift 2; LE_k=006;;
133104*|117104*) shift 2; LE_k=002;;
133110*|117110*) shift 2; LE_k=001;;
133120*|117120*) shift 2; LE_k=004;;
133106*|117106*) shift 2; LE_k=005;;
133061176) shift 3; LE_k=001;;
133064176) shift 3; LE_k=005;;
133063176) shift 3; LE_k=004;;
133*|117*)
shift
while [ "0$1" -ge 060 ] && [ "0$1" -le 071 ] ||
[ "0$1" -eq 073 ]; do
shift
done;;
esac
fi
case $LE_k in
001) # ^A beginning of line
LE_backward "$LE_px"
LE_sx=$LE_px$LE_sx
LE_px=;;
002) # ^B backward
if [ "x$LE_px" = x ]; then
printf '\a'
else
printf '\b'
LE_tmp=${LE_px%?}
LE_sx=${LE_px#"$LE_tmp"}$LE_sx
LE_px=$LE_tmp
fi;;
003) # CTRL-C
break 2;;
004) # ^D del char
if [ "x$LE_sx" = x ]; then
printf '\a'
else
LE_sx=${LE_sx#?}
printf '%s\b' "$LE_sx$LE_fill"
LE_backward "$LE_sx"
fi;;
012|015) # NL or CR
LE_ret=0
break 2;;
005) # ^E end of line
printf %s "$LE_sx"
LE_px=$LE_px$LE_sx
LE_sx=;;
006) # ^F forward
if [ "x$LE_sx" = x ]; then
printf '\a'
else
LE_tmp=${LE_sx#?}
LE_px=$LE_px${LE_sx%"$LE_tmp"}
printf %s "${LE_sx%"$LE_tmp"}"
LE_sx=$LE_tmp
fi;;
010|177) # backspace or del
if [ "x$LE_px" = x ]; then
printf '\a'
else
printf '\b%s\b' "$LE_sx$LE_fill"
LE_backward "$LE_sx"
LE_px=${LE_px%?}
fi;;
013) # ^K kill to end of line
LE_fill "$LE_sx"
LE_backward "$LE_sx"
LE_sx=;;
014) # ^L redraw
printf '\r%b%s' "$LE_prompt" "$LE_px$LE_sx"
LE_backward "$LE_sx";;
025) # ^U kill line
LE_backward "$LE_px"
LE_fill "$LE_px$LE_sx"
LE_backward "$LE_px$LE_sx"
LE_px=
LE_sx=;;
027) # ^W kill word
if [ "x$LE_px" = x ]; then
printf '\a'
else
LE_tmp=${LE_px% *}
LE_backward "${LE_px#"$LE_tmp"}"
LE_fill "${LE_px#"$LE_tmp"}"
LE_backward "${LE_px#"$LE_tmp"}"
LE_px=$LE_tmp
fi;;
[02][4-7]?|[13]??) # 040 -> 177, 240 -> 377
# was assuming iso8859-x at the time
if [ "$LE_max" -ge 0 ] && LE_tmp=$LE_px$LE_sx \
&& [ "${#LE_tmp}" -eq "$LE_max" ]; then
printf '\a'
else
LE_px=$LE_px$(printf '%b' "\0$LE_k")
printf '%b%s' "\0$LE_k" "$LE_sx"
LE_backward "$LE_sx"
fi;;
*)
printf '\a';;
esac
done
done
eval "$LE_restore"
REPLY=$LE_px$LE_sx
echo
return "$LE_ret"
}
Run Code Online (Sandbox Code Playgroud)
用作:
LE 'Prompt: '
Run Code Online (Sandbox Code Playgroud)
或者:
LE 'Prompt: [....]\b\b\b\b\b' 4 . DEF
Run Code Online (Sandbox Code Playgroud)
如果您想要最大长度和/或不同的填充字符和/或初始值。