为什么 $'\0' 与 '' 相同?

slh*_*hck 10 bash

处理几个文件的常用方法是——不要为此打我:

for f in $(ls); do …
Run Code Online (Sandbox Code Playgroud)

现在,为了防止带有空格或其他奇怪字符的文件,一种天真的方法是:

find . -type f -print0 | while IFS= read -r -d '' file; …
Run Code Online (Sandbox Code Playgroud)

在这里,-d ''是设置 ASCII NUL 的缩写,如-d $'\0'

但为什么会这样呢?为什么是''$'\0'一样?这是因为 Bash 的 C 根以空字符串总是以空字符结尾吗?

mic*_*has 10

man page of bash读取:

          -d delim
                 The first character of delim is  used  to  terminate  the
                 input line, rather than newline.
Run Code Online (Sandbox Code Playgroud)

因为字符串通常以空字符结尾,所以空字符串的第一个字符是空字节。- 我感觉合理。:)

消息来源写道:

static unsigned char delim;
[...]
    case 'd':
      delim = *list_optarg;
      break;
Run Code Online (Sandbox Code Playgroud)

对于空字符串delim只是空字节。


Gil*_*il' 6

bash 有两个相互弥补的不足。

写入时$'\0',它在内部被视为与空字符串相同。例如:

$ a=$'\0'; echo ${#a}
0
Run Code Online (Sandbox Code Playgroud)

这是因为 bash 在内部将所有字符串存储为C字符串,这些字符串以空字符结尾——空字节标记字符串的结尾。Bash 默默地将字符串截断到第一个空字节(它不是字符串的一部分!)。

# a=$'foo\0bar'; echo "$a"; echo ${#a}
foo
3
Run Code Online (Sandbox Code Playgroud)

当您将字符串作为参数传递给内置-d选项时read,bash 只查看字符串的第一个字节。但它实际上并没有检查字符串是否为空。在内部,空字符串表示为仅包含空字节的 1 元素字节数组。因此,bash 不是读取字符串的第一个字节,而是读取这个空字节。

然后,在内部,read内置函数背后的机制可以很好地处理空字节;它继续逐字节读取,直到找到分隔符。

其他壳的行为不同。例如,ash 和 ksh 在读取输入时忽略空字节。使用 ksh,ksh -d ""读取直到换行。Shell 旨在很好地处理文本,而不是二进制数据。Zsh 是一个例外:它使用字符串表示来处理任意字节,包括空字节;在 zsh 中,$'\0'是一个长度为 1 的字符串(但read -d ''奇怪的是,它的行为类似于read -d $'\0')。