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

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

bash 手册页对内置函数做了以下说明read

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

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

read -rd '' json <<EOF
{
    "foo":"bar"
}
EOF

我只是不明白为什么在这种情况下需要不成功退出。这在什么情况下有用?

答案1

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

read当它找到 EOF 而尚未遇到记录分隔符时,返回非零。

这允许你做类似的事情

while IFS= read -r line; do
  ...
done < text-file

或者使用 zsh/bash

while IFS= read -rd '' nul_delimited_record; do
  ...
done < null-delimited-list

读取最后一条记录后,该循环将退出。

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

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

无论如何,read不​​设置而使用$IFS几乎没有意义。

有关更多详细信息,请参阅理解“IFS=读取-r行”

答案2

这也是我不使用自己的原因之一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

答案3

默认情况下,读取命令面向来自用户输入的行,但为了使其在文件中工作,它必须能够在到达行尾定界符之前检测文件中的数据何时耗尽。

在您的示例的特定情况下,单词 EOF 用于分隔重定向运算符的内联文本<<并且与读取文档中提到的“文件结束”指示符没有任何关系,除非向解释器发出信号表明数据在最后一行的换行符之后结束(带有右大括号)。当然,由于该构造具有完整的数据并且不是来自文件,因此不可能存在文件结束作为数据突然结束的情况。

因此,读取手册页中的指示在这里没有实际应用,只有当您从文件或数据源读取时,这些文件或数据源可以将结尾标记为 eof(例如用户按 [Ctrl-D] 或到达结尾)管道中的数据来自另一个命令)。

这与 d 和 r 选项的特殊行为相结合: -d 导致读取所有可能的内容而不考虑行尾,并且(我认为这里是必要的) -t 导致读取忽略反斜杠转义字符(不是存在于数据中,并且不需要,因为文本位于引号内,除非“bar”应该具有一些特殊字符,例如嵌入二进制数据或不可打印的字符),因此这显然不适用于作为数据源的文件。

相关内容