读取的静默选项被忽略?

读取的静默选项被忽略?

我在 bash shell 脚本中运行一个循环,直到按下某个键为止(Ctrl-C 对我来说总是很残酷)。尽管我使用 -s 选项read,但单个字符显示在终端中。为什么 -s 选项read没有达到我的预期!

until read -s -n 1 -t 0.01; do 
    echo -n "."
    sleep .5    # actual script code goes here
    done 
echo 

答案1

我很确定这是因为按键是在sleep .5运行时按下的,而不是在运行时按下read的。

更详细地说:当它运行时,read -s -n 1 -t 0.01将终端置于 noecho 模式...0.01 秒,然后超时并重新打开 echo。如果您在那 0.01 秒内键入了一个字符,则该字符不会得到回显,但您可能错过了该窗口。相反,您在sleep .5运行时输入它,因此它会回显。然后半秒后read再次运行,关闭回显(太晚了!),从预输入缓冲区中读取字符,最后重新打开回显。

(注意:该echo命令和 echo 终端模式没有直接联系,除了它们都涉及打印到终端的内容之外。)

解决方案:不要指望read -s关闭回声,而是stty -echo在开始时使用一次(并stty echo在最后将其重新打开)。正如比利叔叔在评论中指出的那样,trap如果脚本由于某种原因异常退出(例如 Control-C),添加 a 以确保终端设置恢复正​​常也是明智的:

trap 'stty echo' EXIT    # If script exits abnormally, fix terminal
stty -echo    # turn off echo
until read -n 1 -t 0.01; do
    echo -n "."
    sleep .5
done
echo
stty echo    # turn echo back on

(您可以trap随后删除它,但这并不重要 - 将终端设置为应该的状态无论如何都是一个非常安全的操作。)

编辑:正如 ilkkachu 在评论中指出的那样,最好完全删除sleep,并使用更长的超时read- 这样当您按下某个键时,它不会等待 0.5 秒才注意到你的按键。您还可以使用更长的超时。我仍然会继续使用stty -echo关闭回声,而不是read -s每次都单独关闭它:

trap 'stty echo' EXIT
stty -echo    # turn off echo
until read -n 1 -t 3600; do    # 1 hour timeout, 'cause why not
    echo -n "."
done
echo
stty echo    # turn echo back on

如果您不需要循环,您可以完全删除它(在这种情况下read -s应该可以正常工作):

read -s -n 1

相关内容