我的脚本(应该)表现不同,这取决于输入流中数据的存在。所以我可以这样调用它:
$ 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
。
为什么实际上没有?
因为这是有记录的工作方式。
如何解决这个问题?
只有当这被认为是一个错误(我怀疑它会)并且 bash 源代码被更改时。
也许有其他解决方案来解决“根据数据的存在而采取不同的行动”的问题吗?
是的,实际上,有一个解决方案。help read
我上面引用的内容之后的下一句话是:
仅当指定文件描述符上的输入可用时才返回成功。
这意味着即使它不读取任何数据,它也可以用来触发对可用数据的实际读取:
read -t 0 && read -d '' myData
[ "$myData" ] && echo "got input" || echo "no input was available"
Run Code Online (Sandbox Code Playgroud)
这样就不会耽搁了。