当我使用空字符串作为参数时,“read”shell 命令的“-d”选项会做什么?

当我使用空字符串作为参数时,“read”shell 命令的“-d”选项会做什么?

当我读书的时候这个答案,作者使用此命令将定界符的结果放入变量中:

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。因此,如果实现不小心防范它并且只选择内存中的第一个字节,它会将\0NUL 视为空字符串的第一个字节。

更仔细地重新阅读问题,您提到:

作者在答案下评论这-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(我最喜欢的工具!)必须为读取/匹配空值做出特殊规定。

相关内容