纯bash:自动循环输入用户输入
我已经做到了这一点,而不必玩stty:
loop=true loopDelay=.05
while $loop; do
trapKey=
if IFS= read -d '' -rsn 1 -t $loopDelay str; then
while IFS= read -d '' -rsn 1 -t .002 chr; do
str+="$chr"
done
case $str in
$'\E[A') trapKey="<UP>" ;;
$'\E[B') trapKey="<DOWN>" ;;
$'\E[C') trapKey="<RIGHT>" ;;
$'\E[D') trapKey="<LEFT>" ;;
q | $'\E') loop=false;echo ;;
* ) trapKey=${str@Q} ;;
esac
fi
if [ "$trapKey" ] ;then
printf "\nDoing something with %s.\n" "$trapKey"
fi
echo -n .
done
这将
- 以非常小的占用空间(最多2毫秒)循环执行
- 响应键盘上的 光标左、光标右、光标上 和 光标下
- 通过按下 Esc 键或 q 键退出循环。
解释:
由于键盘不返回字符而是按下的键,某些键可能会发送多个字符,比如 Home 键应该发送一个转义序列:\e[H
,其中包含3个字符。
为了支持这一点,我使用了一个超小的超时read
命令来构建一个循环:
if IFS= read -d '' -rsn 1 -t $LOOPDELAY str; then
while IFS= read -d '' -rsn 1 -t .002 chr; do
str+="$chr"
done
如果在
$LOOPDELAY
之后没有读取任何字符,则表示没有读取键盘按键。否则,
$str
变量将由所有可以在不到
0.002
秒的时间内访问的
read
字符完成。
更好的版本,支持Fx
键:
#!/bin/bash
loopDelay=.042
printf -v shapes "%b " \\U28{19,38,B0,e0,c4,46,07,0b}
shapes=($shapes)
declare -A csiKeys='( [15~]=F5 [17~]=F6 [18~]=F7 [19~]=F8 [20~]=F9 [21~]=F10
[23~]=F11 [24~]=F12 [A]=UP [B]=DOWN [C]=RIGHT [D]=LEFT [H]=HOME [F]=END
[2~]=INSERT [3~]=DELETE [5~]=PGUP [6~]=PGDOWN )' \
escKeys='( [OP]=F1 [OQ]=F2 [OR]=F3 [OS]=F4 )'
loop=true
while $loop; do
trapKey=
if IFS= read -d '' -rsn 1 -t $loopDelay str; then
while IFS= read -d '' -rsn 1 -t .002 chr; do str+="$chr" ; done
if [[ ${str::2} == $'\e[' ]] && [[ -v "csiKeys['${str:2}']" ]] ;then
trapKey="${csiKeys[${str:2}]}"
elif [[ ${str::1} == $'\e' ]] && [[ -v "escKeys['${str:1}']" ]] ;then
trapKey="${escKeys[${str:1}]}"
elif [[ ${str/$'\e'/q} == q ]];then
printf '"%q" pressed, exit.\n' "$str"
loop=false
else
trapKey=${str@Q}
fi
fi
if [ "$trapKey" ] ;then
printf "Doing something with %s.\n" "$trapKey"
fi
printf >&2 '%s\r' ${shapes[shcnt++%8]}
done
"x$variable" = "x"
而不是更简单的"$variable" = ""
?这样做有什么好处还是只是因为他们学习时就是这样做的? - Vala-g
代替--save
将在macOS和Linux上工作(分别测试了11.4和18.04)。 - mathandy