遇到EOF时“读取”退出1的目的是什么?

jes*_*e_b 11 shell read

bash 手册页说明了有关read内置的以下内容:

退出状态为零,除非遇到文件尾

这最近咬了我,因为我-e设置了选项并使用以下代码:

read -rd '' json <<EOF
{
    "foo":"bar"
}
EOF
Run Code Online (Sandbox Code Playgroud)

我只是不明白为什么在这种情况下非成功退出是可取的。在什么情况下这会有用?

Sté*_*las 21

read读取一条记录(默认为一行,但 ksh93/bash/zsh 允许其他分隔符使用-d,甚至使用 zsh/bash 使用 NUL)并在读取完整记录时返回成功。

read 在尚未遇到记录分隔符的情况下找到 EOF 时返回非零值。

这允许你做这样的事情

while IFS= read -r line; do
  ...
done < text-file
Run Code Online (Sandbox Code Playgroud)

或者使用 zsh/bash

while IFS= read -rd '' nul_delimited_record; do
  ...
done < null-delimited-list
Run Code Online (Sandbox Code Playgroud)

并且在读取最后一条记录后退出该循环。

您仍然可以检查在最后一个完整记录之后是否还有更多数据[ -n "$nul_delimited_record" ]

在您的情况下,read的输入不包含任何记录,因为它不包含任何 NUL 字符。在 中bash,不可能在此处的文档中嵌入 NUL。所以read失败,因为它没有设法读取完整的记录。它仍然存储它在json变量中读取的内容,直到 EOF(在 IFS 处理之后)。

在任何情况下,read不设置$IFS就使用几乎没有意义。

有关更多详细信息,请参阅了解“IFS= read -r line”


gle*_*man 8

这是我不使用set -e自己的原因之一。

既然您知道 read 在没有给定 EOL 分隔符的情况下遇到 EOF 将返回 1,您可以执行以下操作之一:

# depending on the contents of the input, it's an error
# if no data was read:
IFS= read -rd '' json <<EOF || [[ -n $json ]]
...
EOF

# or, you don't care at all how much data was read
IFS= read -rd '' json <<EOF || :
...
EOF
Run Code Online (Sandbox Code Playgroud)