我有一个shell脚本,基本上就像是说:
while true; do
read -r input
if ["$input" = "a"]; then
echo "hello world"
fi
done
这一切都很好,但我意识到在这种情况下必须按ENTER键存在一个严重的问题。我需要的是脚本在按键时响应,而不必按ENTER键。
有没有办法在shell脚本中实现这个功能?
read -rsn1
只期望一个字母(不需等待提交),并保持沉默(不要将该字母写回)。
read -rsn1 -t 5 key
读取一个键到 $key
并退出,否则它会等待 5 秒钟重新渲染状态信息。非常方便,谢谢。 - Gerald-rsk1
。 - pacholik因此最终的工作代码片段如下:
#!/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
trap control_c SIGINT
control_c()
{
stty sane
}
P.S 还有可能你需要在脚本中加入一个睡眠语句,这样就不会消耗所有的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选项的“头部”(一个shell内置命令)返回标准输入的一个字节。如果不包括“stty -icanon”,则脚本会回显按下键的字母,然后等待RETURN(这不是我们想要的)。无论是“head”还是“stty”,都是shell内置命令。接收到按键后,保存并恢复旧的终端设置非常重要。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脚本变得交互式。我希望这能有所帮助。
read -n1 c && printf "%s" "$c"
read -n1 c && printf "\nYou Pressed: %s\n" "$c"
为了防止您的初始按键被回显到屏幕上,请同时添加$ read -n1 c && printf "\nYou Pressed: %s\n" "$c" M You Pressed: M
-s
选项,该选项在read --help
菜单中说明如下:
这是最终的命令:-s do not echo input coming from a terminal
read -sn1 c && printf "You Pressed: %s\n" "$c"
还有一个演示:
您还可以选择将$ read -sn1 c && printf "You Pressed: %s\n" "$c" You Pressed: p
-sn1
参数拆分为两个参数(-s -n1
)以提高清晰度。
read -n1
。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
if
条件中[
和]
周围缺少空格。 - fedorqui