为什么$'\0'和''一样?

为什么$'\0'和''一样?

使用几个文件执行操作的常见方法是——不要为此责备我:

for f in $(ls); do …

现在,为了安全地防范带有空格或其他奇怪字符的文件,一种简单的方法是:

find . -type f -print0 | while IFS= read -r -d '' file; …

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

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

答案1

man page of bash内容如下:

          -d delim
                 The first character of delim is  used  to  terminate  the
                 input line, rather than newline.

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

消息来源写道:

static unsigned char delim;
[...]
    case 'd':
      delim = *list_optarg;
      break;

对于空字符串来说delim就是空字节。

答案2

bash 有两个缺陷可以互相弥补。

当您编写 时$'\0',内部将其视为与空字符串相同。例如:

$ a=$'\0'; echo ${#a}
0

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

# a=$'foo\0bar'; echo "$a"; echo ${#a}
foo
3

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

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

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

相关内容