shell script respond to keypress
我有一个shell脚本,基本上说
1 2 3 4 5 6 | while true; do read -r input if ["$input" ="a"]; then echo"hello world" fi done |
这一切都很好,很好,但我刚刚意识到,在这种情况下,必须击中enter是一个严重的问题。我需要的是脚本在按键时响应,而不必按Enter键。
在shell脚本中是否有实现此功能的方法?
1 | read -rsn1 |
希望只有一封信(不要等待提交),保持沉默(不要写回那封信)。
所以最后的工作片段是:
1 2 3 4 5 6 7 8 | #!/bin/bash while true; do read -rsn1 input if ["$input" ="a" ]; then echo"hello world" fi done |
另一种方法,以非阻塞方式(不确定您是否需要它)。您可以使用stty将最小读取时间设置为0。(如果在之后不使用stty sane,则有点危险)
1 | stty -icanon time 0 min 0 |
然后像正常一样运行循环。不需要-R。
1 2 3 4 5 6 7 | while true; do read input if ["$input" ="a"]; then echo"hello world" fi done |
重要!完成非阻塞后,必须记住将stty设置回正常使用状态。
1 | stty sane |
如果你不这样做,你将看不到终端上的任何东西,它将似乎挂起。
您可能希望为ctrl-c包含一个陷阱,就好像在您将stty恢复正常之前脚本已经退出,您将无法看到您键入的任何内容,并且它将显示终端已经冻结。
1 2 3 4 5 6 | trap control_c SIGINT control_c() { stty sane } |
另外,你可能想在你的脚本中加入一个睡眠语句,这样你就不会耗尽你所有的CPU,因为这将继续以尽可能快的速度运行。
1 | sleep 0.1 |
P.S.S.看来,挂起的问题只有在我使用过的时候才出现——可能不需要像以前那样使用echo。我将把它留在答案中,因为将stty重置为默认值以避免将来的问题仍然是好的。如果您不希望您键入的内容出现在屏幕上,可以使用-echo。
您可以使用此
1 2 3 4 5 6 | getkey() { old_tty_settings=$(stty -g) # Save old settings. stty -icanon Keypress=$(head -c1) stty"$old_tty_settings" # Restore old settings. } |
它暂时关闭终端设置中的"规范模式"(
然后,getkey()可以与"
1 2 3 4 5 | case $Keypress in [Rr]*) Command response for"r" key ;; [Ww]*) Command response for"w" key ;; [Qq]*) Quit or escape command ;; esac |
这种
在我的项目中,我有一种方法可以做到这一点:https://sourceforge.net/p/playshell/code/ci/master/tree/source/keys.sh
每次调用密钥读取时,它都读取一个密钥。对于特殊键,将运行一个特殊的解析循环,以便能够解析它们。
这是它的关键部分:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | 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 |