我想让 bash 脚本在文件描述符(FD)打开时将附加信息输出到大于或等于 3 的文件描述符(FD)。为了测试 FD 是否打开,我设计了以下技巧:
if (printf '' 1>&3) 2>&-; then
# File descriptor 3 is open
else
# File descriptor 3 is not open
fi
Run Code Online (Sandbox Code Playgroud)
这足以满足我的需求,但我很好奇是否有更惯用的方法来测试 FD 是否有效。我特别是约是否存在所述的映射感兴趣fcntl(1)
系统调用到外壳命令,这将允许FD标志的检索(O_WRONLY
和 O_RDWR
测试的FD是否可写,和O_RDONLY
和 O_RDWR
测试的FD是否可读)。
在问题“测试文件描述符是否有效”中,寻求测试是否打开文件描述符。
答案都集中在测试文件描述符是否为输出打开,但如何测试文件描述符是否为输入打开?
这是在另一个问题的答案的评论线程中出现的,答案是这样解释的,
if [ -n "$1" ]; then
# read input from file "$1" (we're assuming it exists)
elif [ ! -t 0 ]; then
# read input from standard input (from pipe or redirection)
else
# no input given (we don't want to read from the terminal)
fi
Run Code Online (Sandbox Code Playgroud)
问题[ ! -t 0 ]
在于,-t
如果文件描述符打开并与终端关联,则测试为真。如果测试为假,则描述符要么关闭,要么不与终端关联(即我们正在从管道或重定向读取)。[ ! -t 0 ]
因此,测试并不能保证文件描述符甚至有效。
如何确定它是否有效(这样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 …