![当我使用空字符串作为参数时,“read”shell 命令的“-d”选项会做什么?](https://linux22.com/image/205595/%E5%BD%93%E6%88%91%E4%BD%BF%E7%94%A8%E7%A9%BA%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%BD%9C%E4%B8%BA%E5%8F%82%E6%95%B0%E6%97%B6%EF%BC%8C%E2%80%9Cread%E2%80%9Dshell%20%E5%91%BD%E4%BB%A4%E7%9A%84%E2%80%9C-d%E2%80%9D%E9%80%89%E9%A1%B9%E4%BC%9A%E5%81%9A%E4%BB%80%E4%B9%88%EF%BC%9F.png)
当我读书的时候这个答案,作者使用此命令将定界符的结果放入变量中:
read -r -d '' VAR <<'EOF'
abc'asdf"
$(dont-execute-this)
foo"bar"''
EOF
我对这个选项有点困惑-d
。从该命令的帮助文本中read
:
-d delim
continue until the first character of DELIM is read, rather than newline
所以如果我将空字符串传递给-d
,则意味着读取直到第一个空字符串。这是什么意思?作者在答案下评论说-d ''
使用NUL字符串作为分隔符。这是真的吗(空字符串意味着 NUL 字符串)?为什么不使用类似-d '\0'
或-d '\x0'
等的东西?
答案1
大多数情况下,它的意思就是它所说的,例如:
$ 读取 -d .变量;回声; echo“读取:'$var'” 富。 读:'foo'
阅读立即在 处结束.
,我没有在那里按回车键。
但read -d ''
情况有点特殊,在线参考手册说:
-d delim
delim的第一个字符用于终止输入行,而不是换行符。如果 delim 是空字符串,则 read 将在读取 NUL 字符时终止一行。
\0
表示 中的 NUL 字节printf
,因此我们有例如:
$ printf 'foo\0bar\0' | while read -d '' var; do echo "read: '$var'"; done
read: 'foo'
read: 'bar'
在您的示例中,read -d ''
用于防止换行符成为分隔符,从而允许它一次性读取多行字符串,而不是一次读取一行。
我认为一些旧版本的文档没有明确提及-d ''
.该行为最初可能是 Bash 以 C 方式存储字符串(尾随 NUL 字节)的意外巧合。字符串foo
存储为foo\0
,空字符串存储为 just \0
。因此,如果实现不小心防范它并且只选择内存中的第一个字节,它会将\0
NUL 视为空字符串的第一个字节。
更仔细地重新阅读问题,您提到:
作者在答案下评论这
-d ''
意味着使用NUL 字符串作为分隔符。
这并不完全正确。空字符串(在 POSIX 术语中)表示空字符串,即不包含任何内容、长度为零的字符串。这与空字节,它是二进制值零(*)的单个字节。如果您使用空字符串作为分隔符,您会发现它几乎无处不在,在每个可能的位置。我认为这在 shell 中是不可能的,但是例如在 Perl 中可以像这样分割字符串,例如:
$ perl -le 'print join ":", split "", "foobar";'
f:o:o:b:a:r
read -d ''
使用 NUL字节作为分隔符。
(*与特点 0
, 当然。)
为什么不使用类似
-d '\0'
或-d '\x0'
等的东西?
嗯,这是个好问题。正如 Stéphane 所评论的,最初,ksh93read -d
不支持read -d ''
这样的,将其更改为支持反斜杠转义将与原始版本不兼容。但是你能如果您更喜欢它,仍然可以使用read -d $'\0'
(以及类似的$'\t'
选项卡等)。只是在幕后,这与 相同-d ''
,因为 Bash 不支持字符串中的 NUL 字节。 Zsh 确实如此,但它似乎同时接受-d ''
和-d $'\0'
。
答案2
只是为了指出 ascii 0 作为文件中的字符的特殊性。 Expect(我最喜欢的工具!)必须为读取/匹配空值做出特殊规定。