在管道中使用名称中包含空格的文件

在管道中使用名称中包含空格的文件

我有一个名为的文件夹play,其中包含一个文件damn file(带空格)。当我使用find并将输出传送到tar

find play/ -name 'damn*' | tar cf archive.tar -T -

它工作完美。为什么这有效 的输出find包含应该导致问题的空间tar。当我使用这个命令时:

tar cf archive.tar $(find play/ -name 'damn*')

bash 显示这些错误:

tar: play/damn: Cannot stat: No such file or directory
tar: file: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors

我很困惑。为什么第一个例子有效?

答案1

在第二个示例中,换行符被 shell 删除,shell 对命令替换的输出进行分词。由于默认情况下包含换行符IFS,因此它们被视为字段分隔符,而不是字段本身的一部分。在第一个示例中,输入来自管道而不是 shell,因此 shell 无法进行分词。

双引号命令替换 ( "$(find ... )") 将防止发生分词,但find内部命令替换几乎总是坏的想法所以不要这样做。为了获得最大的安全性,只要您可以访问 GNU 版本的 Unix 工具,您就应该使用空分隔符选项:

find dir/ -name '...' -print0 | tar cf foo.tar --null --no-recursion -T -

答案2

find play/ -name 'damn*'将生成一个文件名列表,每行 1 个。如果play/damn file是唯一匹配的文件,那么它相当于echo 'play/damn file'.

焦油的-T选项期望文件名由换行符分隔。任何其他空格都被视为文件名的一部分。这就是为什么你的第一个例子有效。

当你使用$(...),命令的输出是按空格分割由 shell 处理,然后每个单词都成为 的参数tar。因此,play/damnfile成为两个参数,并且都不是现有文件。

相关内容