我有一个shell脚本,基本上说的是
while true; do
read -r input
if ["$input" = "a"]; then
echo "hello world"
fi
done
这一切都很好,很好,但我只是意识到必须点击ENTER在这种情况下出现严重问题。我需要的是脚本在按下键时响应,而不必按Enter键。
有没有办法在shell脚本中实现此功能?
答案 0 :(得分:21)
read -rsn1
期待只有一个字母(并且不要等待提交)并保持沉默(不要写回那封信)。
答案 1 :(得分:10)
所以最终的工作片段如下:
#!/bin/bash
while true; do
read -rsn1 input
if [ "$input" = "a" ]; then
echo "hello world"
fi
done
答案 2 :(得分:4)
另一种方式,以非阻塞的方式(不确定它是否是你想要的)。您可以使用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。
答案 3 :(得分:2)
您可以使用此getkey
功能:
getkey() {
old_tty_settings=$(stty -g) # Save old settings.
stty -icanon
Keypress=$(head -c1)
stty "$old_tty_settings" # Restore old settings.
}
暂时关闭"规范模式"在终端设置中
(stty -icanon
)然后返回" head"的输入。 (内置shell),带有-c1选项,返回标准输入的一个字节。如果你不包括" stty -icanon"然后脚本回显按下的键的字母,然后等待RETURN(不是我们想要的)。两者都是"头和#34;和" 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脚本具有交互性。我希望这会有所帮助。
答案 4 :(得分:1)
我有办法在我的项目中执行此操作: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