Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash shell脚本响应按键_Bash_Shell_Input_Keypress - Fatal编程技术网

Bash shell脚本响应按键

Bash shell脚本响应按键,bash,shell,input,keypress,Bash,Shell,Input,Keypress,我有一个shell脚本,基本上说 while true; do read -r input if ["$input" = "a"]; then echo "hello world" fi done 这一切都很好,但我刚刚意识到,在这种情况下,必须按回车键是一个严重的问题。我需要的是脚本在按下键时做出响应,而不必按enter键 有没有办法在shell脚本中实现此功能 read -rsn1 只希望收到一封信(不要等待提交),保持沉默

我有一个shell脚本,基本上说

while true; do
    read -r input
    if ["$input" = "a"]; then 
        echo "hello world"           
    fi
done
这一切都很好,但我刚刚意识到,在这种情况下,必须按回车键是一个严重的问题。我需要的是脚本在按下键时做出响应,而不必按enter键

有没有办法在shell脚本中实现此功能

read -rsn1

只希望收到一封信(不要等待提交),保持沉默(不要回信)。

在我的项目中,我有办法做到这一点:

每次调用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

另一种方法是,以非阻塞方式(不确定这是否是您想要的)。您可以使用stty将最小读取时间设置为0。(如果之后未使用stty sane,则有点危险)

然后像平常一样运行你的循环。不需要-r

while true; do
    read input

    if ["$input" = "a"]; then 
        echo "hello world"           
    fi
done
重要! 完成非阻塞后,必须记住使用

stty sane
如果你不这样做,你将看不到终端上的任何东西,它将出现挂起

您可能希望为ctrl-C添加一个陷阱,就好像在将stty恢复到正常状态之前脚本已退出一样。您将无法看到您键入的任何内容,并且终端似乎已冻结

trap control_c SIGINT

control_c()
{
    stty sane
}
另外,你可能想在你的脚本中加入一个sleep语句,这样你就不会耗尽你所有的CPU,因为它会以尽可能快的速度持续运行

sleep 0.1
另外,这个悬而未决的问题似乎只是在我使用-echo时出现的,因为我以前使用过-echo,所以可能不需要。我将把它留在答案中,因为将stty重置为默认值以避免将来的问题仍然是好的。
如果您不希望您键入的内容显示在屏幕上,可以使用-echo。

因此,最后的工作片段如下所示:

#!/bin/bash

while true; do
read -rsn1 input
if [ "$input" = "a" ]; then
    echo "hello world"
fi
done

您可以使用此
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”,那么脚本会回显按键的字母,然后等待返回(不是我们想要的)。“head”和“stty”都是shell内置命令。收到按键后,保存和恢复旧的终端设置非常重要

然后,getkey()可以与“
case/esac
”语句结合使用,用于从条目列表中进行交互式单键选择: 例如:


这种
getkey()/case-esac
组合可用于使许多shell脚本交互。我希望这会有所帮助。

如果这是您的真实代码,请注意,您在
if
条件中遗漏了
[
]
周围的空格。不,这不是我的真实代码。但是感谢tipThe,脚本的应用程序正在显示中。前一个控制面板是用鼠标制作的,点击作为操作机构。但他们想为数据存储增加一个硬币。原来的电脑已经死掉了,并且一直在运行windows 98,并且所有的硬件或软件都不能在新的windows操作系统上运行。因此,我推导了各个操作,并重新连接了一个键盘,以提供IO功能。但是,当我回家编写脚本的其余部分,远程登录时,它似乎不起作用。观众是儿童。随机复制特殊密钥子集的风险很大:伙计,我昨晚试过了,但似乎不起作用。但延迟可能是个问题。我会再试一次。@j0h是否继续循环,因为这将阻止输入内容?我想让它反复询问用户:在完成每个步骤后,他们为什么要这样做。不幸的是,我仍然在家,在windows计算机上。如果您需要检查输入是否可用,请尝试添加
-t0.01
以等待几秒钟,如果没有按键等待,请放弃。如果你想要一个非常紧密的循环,更小的数字可能是完全可以的。非正式的实验表明0.00001可以工作,但是0.000001太小了。我使用这个命令创建了一个自我更新的状态信息脚本,它可以接受按键输入来更改显示
read-rsn1-t5键
将一个键读取到
$key
并退出,否则它将等待5秒钟重新呈现状态信息。非常方便,谢谢。getkey()的可用性各不相同。
getkey() {
    old_tty_settings=$(stty -g)   # Save old settings.
    stty -icanon
    Keypress=$(head -c1)
    stty "$old_tty_settings"      # Restore old settings.
}
case $Keypress in
   [Rr]*) Command response for "r" key ;;
   [Ww]*) Command response for "w" key ;;
   [Qq]*) Quit or escape command ;;  
esac