gpt4 book ai didi

Bash:读取输入可用(是否按下任何键?)

转载 作者:行者123 更新时间:2023-12-04 15:41:05 25 4
gpt4 key购买 nike

问题

我正在使用 Bash 5 并且有一个长时间运行的循环,需要偶尔检查用户可能按下的各种键。我知道如何使用 stty 来做到这一点——请参阅下面我的回答——但它比应该的更难看。

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

keyhit-p() {
if "read -n1 would block"; then
return false
else
return true
fi
}

非解:read -t 0

我已经阅读了bash 手册并且了解read -t 0。这不符合我的要求,即检测任何 输入是否可用。相反,它仅在用户按下 ENTER(完整的输入行)时返回 true。

例如:

while true; do
if read -n1 -t0; then
echo "This only works if you hit enter"
break
fi
done

最佳答案

一个有效的答案,虽然丑陋

虽然以下工作正常,但我希望有人能提供更好的答案。

#!/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

这会在 read 之前更改用户的终端设置 (stty) 并尝试在之后将它们写回,但这样做是非原子的。脚本可能会被中断并使用户的终端处于不正确的状态。我希望看到解决该问题的答案,最好只使用 bash 内置的工具。

更快,甚至更丑陋的答案

上述例程的另一个缺陷是它需要大量的 CPU 时间来尝试使一切正确。它需要调用一个外部程序 (stty) 三次来检查是否没有发生任何事情。循环中的 fork 可能很昂贵。如果我们放弃正确性,我们可以获得一个运行速度快两个数量级 (256×) 的例程。

#!/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

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

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

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

关于Bash:读取输入可用(是否按下任何键?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57760967/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com