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


10

处理几个文件的一种常见方法是-不要为此而生:

for f in $(ls); do 

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

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

此处-d ''是,用于将ASCII NUL设置为的缩写-d $'\0'

但是为什么会这样呢?为什么''$'\0'一样?是因为Bash的C根目录带有空字符串始终以空值结尾吗?


提到“天真的”方式,有没有更好的方法呢?
iruvar

2
顺便说一句,如果您想对一组文件进行安全操作,请使用for f in *而不是解析ls

我知道@htor for i in $(ls)非常愚蠢-我在这里用它作为一个不好的例子时几乎感到ham 愧。
slhck

@ChandraRavoori是的,例如,通过使用find … -exec而不是在文件周围循环,这在大多数情况下可以使用这样的for循环来工作。在这里,find为您照顾一切。
slhck

@slhck,谢谢。对于涉及每个文件的多步操作的情况,出于可读性原因,最好使用循环呢?是否有比上述“天真的方法”更好的循环选项?
iruvar

Answers:


10

man page of bash读取:

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

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

资料来源:

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

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


当您说“字符串通常以null终止”时,在POSIX环境中的某些地方不是这样吗?从我在学校学习C的那一天开始,当然就应该这样假设。我只是在检查。
slhck

但是,可以将任何字符串视为包含任意多个空字符串,例如,如果将”和“ X”串联在一起,则会得到“ X”。因此,您可能会争辩说,第一个子字符串bash遇到的是空字符串。例如,如果您在javascript中使用空字符串,split()它将在每个字符之间分割。我怀疑“出于历史原因”可能是我们可以获得的最好解释。
donothingsuccessly 2013年

好吧,这并不是完全正确的,因为“将C样式'\0'与”连接起来'X\0'可以为您带来'X\0'好处。这并没有太多的语言,如JavaScript @don与高级功能做
slhck

谢谢,michas,添加了源。delim = *list_optarg;明确说明为什么会这样。
slhck

@slhck:对不起,我没有说清楚。您问“为什么''$'\0'相同?”,michas给出了“这就是代码的作用”的直接解释。我概述了处理空字符串的另一种方法,该方法我认为同样合理,并建议选择一个或另一个仅是约定或偶然性问题。
donothingsuccessly 2013年

6

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

当您编写时$'\0',它在内部与空字符串相同。例如:

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

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

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

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

然后,在内部,read内置的机器可以很好地处理空字节;它一直在逐字节读取直到找到定界符。

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


read在bash 4.3 中更改的行为,因此现在跳过空字节。例如read x< <(printf a\\0a)设置xaa而不是a
Lri 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.