我有一个shell脚本,基本上就是这样的
while true; do
read -r input
if ["$input" = "a"]; then
echo "hello world"
fi
done
这一切都很好,很好,但我只是意识到必须点击ENTER在这种情况下提出了一个严重的问题。我需要的是脚本在按下键时响应,而不必按Enter键。
有没有办法在shell脚本中实现此功能?
read -rsn1
期待只有一个字母(并且不要等待提交)并保持沉默(不要写回那封信)。
所以最后的工作片段如下:
#!/bin/bash
while true; do
read -rsn1 input
if [ "$input" = "a" ]; then
echo "hello world"
fi
done
另一种方式,以非阻塞的方式(不确定它是否是你想要的)。您可以使用stty将最小读取时间设置为0.(如果之后没有使用stty sane,则有点危险)
stty -icanon time 0 min 0
然后就像正常一样运行循环。不需要-r。
while true; do
read input
if ["$input" = "a"]; then
echo "hello world"
fi
done
重要!完成非阻塞后,您必须记住使用stty设置恢复正常
stty sane
如果你没有,你将无法在终端上看到任何东西,它似乎会挂起。
你可能想要为ctrl-C包含一个陷阱,就好像在你将stty恢复到正常状态之前退出脚本一样,你将无法看到你键入的任何东西,并且它将显示终端已经冻结。
trap control_c SIGINT
control_c()
{
stty sane
}
P.S此外,您可能希望在脚本中放置一个sleep语句,这样就不会耗尽所有CPU,因为这样可以尽可能快地运行。
sleep 0.1
P.S.S似乎悬挂的问题只有在我使用-echo的时候,因为我以前可能不需要。我将把它留在答案中,因为将stty重置为默认值以避免将来出现问题仍然很好。如果你不想要你输入的内容出现在屏幕上,你可以使用-echo。
你可以使用这个getkey
函数:
getkey() {
old_tty_settings=$(stty -g) # Save old settings.
stty -icanon
Keypress=$(head -c1)
stty "$old_tty_settings" # Restore old settings.
}
它暂时关闭终端设置(stty -icanon
)中的“规范模式”,然后使用-c1选项返回“head”(内置shell)的输入,该选项返回标准输入的一个字节。如果您不包含“stty -icanon”,则脚本会回显按下的键的字母,然后等待RETURN(不是我们想要的)。 “head”和“stty”都是shell内置命令。收到按键后保存和恢复旧的终端设置非常重要。
然后,getkey()可以与“case / esac
”语句结合使用,以便从条目列表中进行交互式一键选择:示例:
case $Keypress in
[Rr]*) Command response for "r" key ;;
[Ww]*) Command response for "w" key ;;
[Qq]*) Quit or escape command ;;
esac
这个getkey()/case-esac
组合可用于使许多shell脚本交互。我希望这有帮助。
我有办法在我的项目中执行此操作:https://sourceforge.net/p/playshell/code/ci/master/tree/source/keys.sh
每次调用key_readonce时它都会读取一个键。对于特殊键,运行一个特殊的解析循环也可以解析它们。
这是它的关键部分:
if read -rn 1 -d '' "${T[@]}" "${S[@]}" K; then
KEY[0]=$K
if [[ $K == $'\e' ]]; then
if [[ BASH_VERSINFO -ge 4 ]]; then
T=(-t 0.05)
else
T=(-t 1)
fi
if read -rn 1 -d '' "${T[@]}" "${S[@]}" K; then
case "$K" in
\[)
KEY[1]=$K
local -i I=2
while
read -rn 1 -d '' "${T[@]}" "${S[@]}" "KEY[$I]" && \
[[ ${KEY[I]} != [[:upper:]~] ]]
do
(( ++I ))
done
;;
O)
KEY[1]=$K
read -rn 1 -d '' "${T[@]}" 'KEY[2]'
;;
[[:print:]]|$'\t'|$'\e')
KEY[1]=$K
;;
*)
__V1=$K
;;
esac
fi
fi
utils_implode KEY __V0