bash read -d '' 的作用是什么?

What does the bash read -d '' do?

-d '' 在 bash 读取命令中的作用是什么?该示例直接来自 a previous SO。从 read 命令打印的用法来看,它说 -d 选项定义了一行中用于拆分单词的分隔符。空分隔符有什么作用?

read -d '' sql << EOF
select c1, c2 from foo
where c1='something'
EOF

echo "$sql"

我通过实验知道用它为变量分配了多行。没有它,只会分配第一行。似乎很难根据用法文本来解释这种行为。

In bash read 内置空字符串分隔符 -d '' 与使用分隔符作为 NUL 字节或 $'[=14=]' 的行为相同(由 ANSI C 引号字符串定义)或十六进制表示 0x0.

-d '' 指定每个输入行应由 NUL 字节分隔。这意味着在每次调用 read.

时,输入字符串被读取到紧邻的下一个 NUL 字符

通常与IFS=一起使用:

IFS= read -r -d ''

用于修剪输入中的前导和尾随空格。

处理 NUL 分隔输入的常见示例是:

while IFS= read -r -d '' file; do
    echo "$file"
done < <(find . -type f -print0)
  • find 命令正在打印当前目录中的文件,每个条目之间以 NUL 作为分隔符。
  • read -d ''[=21=] 设置为分隔符,用于从 find 命令的输出中一次读取一个条目。

相关:

read -d 将停止读取的字符从默认换行符更改为以下参数的第一个字符。

要理解的重要一点是 bash 使用 C 字符串,这些字符串由文字 NUL 终止。因此,当后面的参数是 '' 时,第一个(也是唯一的)字符是终止它的 NUL;因此,当 shell 取消引用 char* 以获取它指向的第一个字符时,它会得到一个 NUL。


现在,当您使用 <<EOF 重定向 heredoc 时,该文档实际上不会包含任何 NUL -- 那么您的代码如何工作?

答案是您的代码预计read 操作会失败。即使失败,read 仍会填充其目标变量;所以如果你没有终止分隔符,read 有一个非零退出状态......但它仍然把你想要收集的所有数据无论如何都放在变量中!

对于不触发set -e错误的版本,考虑读取完成后检查目标变量是否为空:

{ IFS= read -r -d '' string || [[ $string ]]; } <<'EOF'
...string goes here...
EOF

我们做了哪些改变?

  • IFS= 防止去除前导或尾随空格(或其他字符,如果 IFS 已重新定义)。
  • read -r 防止带有反斜杠文字的内容被破坏。
  • || [[ $string ]] 表示如果 read 报告失败,我们将检查字符串是否已填充,如果变量不为空,则仍然认为整个命令成功。