为什么 bash "read -t 0" 看不到输入?

Cro*_*max 5 bash read

我的脚本(应该)表现不同,这取决于输入流中数据的存在。所以我可以这样调用它:

$ my-script.sh
Run Code Online (Sandbox Code Playgroud)

或者:

$ my-script.sh <<-MARK
    Data comes...
    ...data goes.
MARK
Run Code Online (Sandbox Code Playgroud)

或者:

$ some-command | my-script.sh
Run Code Online (Sandbox Code Playgroud)

其中最后两个案例应该读取数据,而第一个案例应该注意到数据丢失并采取相应措施。

脚本的关键部分(摘录)是:

$ my-script.sh
Run Code Online (Sandbox Code Playgroud)

我使用read读取输入数据,然后选择-d ''读取多行,正如预期的那样,并将-t 0超时设置为零。为什么超时?根据help read(打字保持不变;粗体是我的):

-t timeout如果未在几TIMEOUT秒钟内读取完整的输入行,则超时并返回失败。TMOUT 变量的值是默认超时。 TIMEOUT可能是小数。 如果TIMEOUT为 0,则仅当指定文件描述符上的输入可用时 read 才返回成功。如果超时,则退出状态大于 128

所以我在情况 2 和 3 中应该立即读取数据,据我所知。不幸的是它没有。由于-t可以采用小数值(根据上面的手册页),将读取行更改为:

$ my-script.sh <<-MARK
    Data comes...
    ...data goes.
MARK
Run Code Online (Sandbox Code Playgroud)

当数据存在时实际读取数据,如果不存在则跳过它(在 10ms 超时后)。但它也应该在TIMEOUT设置为 real时工作0

为什么它实际上没有?如何解决这个问题?对于“根据数据的存在而采取不同行动”的问题,是否有替代解决方案?

更新

感谢@Isaac,我发现引用的在线版本和我的本地版本之间存在误导性差异(通常我没有将语言环境设置为 en_US,所以help read给了我无法粘贴在这里的翻译,并查找在线翻译比设置新环境更快——但这导致了整个问题)。

所以对于 4.4.12 版本的 Bash 它说:

如果 TIMEOUT 为 0,则 read 立即返回,不尝试读取任何数据,仅当指定文件描述符上的输入可用时才返回成功。

这给人的印象与“如果 TIMEOUT 为 0,仅当输入在指定的文件描述符上可用时才返回成功”的印象略有不同——对我来说,它实际上暗示了读取数据的尝试。

所以最后我测试了这个并且它工作得很好:

$ some-command | my-script.sh
Run Code Online (Sandbox Code Playgroud)

意思是:看看有没有什么要读的,如果成功了,就读吧。

为了基本问题,艾萨克提供了正确的答案。至于替代解决方案,我更喜欢上面的“read && read”方法。

小智 3

不,read -t 0不会读取任何数据。

您正在阅读错误的手册。将man read给出 PATH 中名为 的程序的手册read这不是内置bash的手册read

要阅读 bash 手册页,请使用man bash并搜索read [-ers]或简单地使用:

help read
Run Code Online (Sandbox Code Playgroud)

其中包含此内容(在版本 4.4 上):

如果超时为 0,则 read 立即返回,而不尝试读取任何数据。

所以,不,不会使用 读取任何数据-t 0


  1. Q1

    为什么实际上没有?

因为这是有记录的工作方式。

  1. Q2

    如何解决这个问题?

只有当这被认为是一个错误(我怀疑它会)并且 bash 源代码被更改时。

  1. 第三季度

    也许有其他解决方案来解决“根据数据的存在而采取不同的行动”的问题吗?

是的,实际上,有一个解决方案。help read我上面引用的内容之后的下一句话是:

仅当指定文件描述符上的输入可用时才返回成功。

这意味着即使它不读取任何数据,它也可以用来触发对可用数据的实际读取:

read -t 0 && read -d '' myData

[ "$myData" ] && echo "got input" || echo "no input was available"
Run Code Online (Sandbox Code Playgroud)

这样就不会耽搁了。