Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jsp/3.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:读取输入可用(是否有任何键命中?) 问题:_Bash_Unix_Nonblocking_Stty - Fatal编程技术网

Bash:读取输入可用(是否有任何键命中?) 问题:

Bash:读取输入可用(是否有任何键命中?) 问题:,bash,unix,nonblocking,stty,Bash,Unix,Nonblocking,Stty,我正在使用Bash5,有一个长时间运行的循环,需要偶尔检查用户可能碰到的各种键。我知道如何使用stty-见下面我的答案-但它比应该的更难看 基本上,我正在寻找一种干净的方法来做到这一点: keyhit-p(){ 如果“read-n1将阻塞”;则 返回错误 其他的 返回真值 fi } 非解决方案:读取-t0 我已经阅读了bash手册,了解了read-t0。这并不是我想要的,也就是检测是否有任何输入可用。相反,只有当用户点击ENTER(完整的输入行)时,它才会返回true 例如: 为true时;做

我正在使用Bash5,有一个长时间运行的循环,需要偶尔检查用户可能碰到的各种键。我知道如何使用
stty
-见下面我的答案-但它比应该的更难看

基本上,我正在寻找一种干净的方法来做到这一点:

keyhit-p(){
如果“read-n1将阻塞”;则
返回错误
其他的
返回真值
fi
}
非解决方案:读取-t0 我已经阅读了
bash
手册,了解了
read-t0
。这并不是我想要的,也就是检测是否有任何输入可用。相反,只有当用户点击ENTER(完整的输入行)时,它才会返回true

例如:

为true时;做
如果读取-n1-t0;然后
echo“仅当您按enter键时,此选项才起作用”
打破
fi
完成
一个有效的答案,尽管很难看 虽然下面的工作,我希望有人有一个更好的答案

#!/bin/bash
# Reset terminal's stty to previous values on exit.
trap 'stty $(stty --save)' EXIT

keyhit-p() {
    # Return true if input is available on stdin (any key has been hit).
    local sttysave=$(stty --save)
    stty -icanon min 1 time 0   # ⎫
    read -t0                    # ⎬ Ugly: This ought to be atomic so the
    local status=$?             # ⎪ terminal's stty is always restored.
    stty $sttysave              # ⎭
    return $status
}

while true; do
    echo -n .
    if ! keyhit-p; then
        continue
    else
        while keyhit-p; do
            read -n1
            echo Key: $REPLY
        done
        break
    fi
done

这会在
读取之前更改用户的终端设置(stty),并在读取之后尝试将其写回,但不会以原子方式进行。脚本可能会被中断,并使用户终端处于不正确的状态。我希望看到一个解决这个问题的答案,最好只使用bash内置的工具

更快、更难看的回答 上述例程中的另一个缺陷是,要想让一切正常,需要花费大量CPU时间。它需要调用一个外部程序(
stty
)三次,以检查是否没有发生任何事情。叉子在环中可能很贵。如果不考虑正确性,我们可以得到一个运行速度快两个数量级(256×)的例程

与仅在读取测试期间更改为非规范模式不同,此脚本在开始时设置一次,并在脚本退出时使用异常处理程序撤消它

虽然我喜欢代码看起来更干净,但由于未处理挂起信号,原始版本的原子性缺陷更加严重。如果用户的shell是bash,则在进程挂起时启用icanon,但在进程预先固定时不禁用icanon。这使得
read-t0
即使在按下键(而不是回车键)时也返回FALSE。其他用户shell可能不会像bash那样在^Z上启用icanon,但更糟糕的是,输入命令将不再像往常一样工作


此外,要求非规范模式始终保持打开状态可能会导致其他问题,因为脚本比这个简单的示例要长。没有记录非规范模式如何影响
读取
和其他bash内置。它似乎在我的测试中起作用,但它会一直起作用吗?调用外部程序或被外部程序调用时,遇到问题的可能性会成倍增加。可能不会出现问题,但需要进行繁琐的测试。

尽管这样做有意义,但请注意添加
-n1
无助于通知bash我计划一次读取一个字符,而不是逐行读取。也许这应该是一个bash功能请求?丑陋是什么意思?“丑陋”如“将stty状态保存在变量中,然后希望在用户点击^C之前恢复它,使其终端损坏”。这应该是一个原子行动。我知道我可以
捕获退出'stty sane'
,但这使得关于用户终端的假设并不总是有效的。
#!/bin/bash

# Reset terminal's stty to previous values on exit.
trap 'stty $(stty --save)' EXIT

# Set one character at a time input for the whole script.
stty -icanon min 1 time 0

while true; do
    echo -n .
    # We save time by presuming `read -t0` no longer waits for lines.
    # This may cause problems and can be wrong, for example, with ^Z.
    if ! read -t0; then
        continue
    else
        while read -t0; do
            read -n1
            echo Key: $REPLY
        done
        break
    fi
done