-d ''
在 bash read 命令中是什么意思?这个例子直接来自之前的 SO 问题。从 read 命令打印的用法来看,它说 -d
选项定义了行内分隔单词的分隔符。空分隔符是什么意思?
read -d '' sql << EOF
select c1, c2 from foo
where c1='something'
EOF
echo "$sql"
我通过实验知道,使用它后,变量被分配了多行。如果没有使用它,则只会分配第一行。基于使用文本来解释这种行为似乎很困难。
read -d
可以改变 read 命令停止读取的字符,从默认的换行符变成下一个参数的第一个字符。
需要理解的是,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
报告失败,则我们检查字符串是否已填充,并且仍然认为变量非空时整个命令成功。read -d $'\0'
与 set -e
不兼容。而且当 read
返回非零时,它甚至没有打印错误消息的礼貌 :-) - Iain Samuel McLean Elderread
内置的空字符串分隔符-d ''
的行为与使用NUL字节或用ANSI C引用的字符串定义的$'\0'
(即十六进制表示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 ''
将 \0
设置为从 find
命令的输出中读取一个条目的分隔符。$'\0'
是具有误导性的,因为它的使用暗示它正在生成与''
不同的东西,并且bash能够在字符串中表示NUL字面值。 - Charles Duffy$'\0'
是具有误导性的,但是无论我们使用 -d ''
还是 -d $'0'
,bash
的行为都是相同的。 - anubhava
\0
是 NUL 字符。 - anubhava'\0'
,而变量则不行。这个问题在以下链接中有更详细的讨论:如何在bash中处理以null字符分隔的输入 和 如何读取以null字符分隔的字段。我会进一步研究这个问题。 - minghua'\0'
不是空字符字面值;它只是一个转义序列,printf
会将其转换为空字符。 - Charles Duffy