我读过,因为 Bash 中的文件路径可以包含除空字节(零值字节$'\0'
)之外的任何字符,所以最好使用空字节作为分隔符。例如,如果将 的输出find
发送到另一个程序,则建议使用该-print0
选项(对于find
具有它的版本)。
但是,虽然这样的事情工作正常(打印由换行符分隔的文件路径 - 别担心,这只是一个演示,我实际上并没有在实际脚本中这样做):
find -print0 \
| while IFS= read -r -d $'\0' ; do echo "$REPLY" ; done
Run Code Online (Sandbox Code Playgroud)
这样的事情就不会工作:
for file in * ; do echo -n "$file"$'\0' ; done \
| while IFS= read -r -d $'\0' ; do echo "$REPLY" ; done
Run Code Online (Sandbox Code Playgroud)
当我只尝试for
-loop 部分时,我发现它只是将所有文件名打印在一起,中间没有空字节。
为什么是这样?这是怎么回事?
我不明白管道中的数据是如何流动的,希望有人能澄清那里发生了什么。
我认为命令管道以逐行方式处理文件(文本、字符串数组)。(如果每个命令本身逐行工作。)每行文本都通过管道,命令不会等待前一个完成处理整个输入。
但似乎并非如此。
这是一个测试示例。有几行文字。我将它们大写并重复每行两次。我这样做cat text | tr '[:lower:]' '[:upper:]' | sed 'p'
。
为了遵循这个过程,我们可以“交互地”运行它——跳过cat
. 管道的每个部分逐行运行:
$ cat | tr '[:lower:]' '[:upper:]'
alkjsd
ALKJSD
sdkj
SDKJ
$ cat | sed 'p'
line1
line1
line1
line 2
line 2
line 2
Run Code Online (Sandbox Code Playgroud)
但是完整的管道确实等待我完成输入,EOF
然后才打印结果:
$ cat | tr '[:lower:]' '[:upper:]' | sed 'p'
I am writing...
keep writing...
now ctrl-D
I AM WRITING...
I AM WRITING...
KEEP WRITING...
KEEP WRITING...
NOW CTRL-D
NOW CTRL-D
Run Code Online (Sandbox Code Playgroud)
应该是这样吗?为什么不是一行一行的?