带引号的文件,空格导致xargs出现不良行为

时间:2017-02-22 22:07:56

标签: bash shell sh xargs

我想find一些文件,并使用管道命令计算shasum

find . -type f | xargs shasum

但是我的目录中有文件带引号,例如名为

的文件
file with "special" characters.txt

管道输出如下所示:

user@home ~ $ find . -type f | xargs shasum
da39a3ee5e6b4b0d3255bfef95601890afd80709  ./empty1.txt
da39a3ee5e6b4b0d3255bfef95601890afd80709  ./empty2.txt
da39a3ee5e6b4b0d3255bfef95601890afd80709  ./empty3.txt
shasum: ./file: 
shasum: with: No such file or directory
shasum: special: No such file or directory
shasum: characters.txt: No such file or directory
25ea78ccd362e1903c4a10201092edeb83912d78  ./file1.txt
25ea78ccd362e1903c4a10201092edeb83912d78  ./file2.txt

文件名中的引号会产生问题。

如何告诉shasum正确处理文件?

1 个答案:

答案 0 :(得分:5)

简短的解释是,xargs被广泛认为是按设计划分的,除非使用标准的扩展来禁用其尝试解析和兑现引用和转义内容的行为它的输入。有关详细信息,请参阅the xargs section of UsingFind

使用NUL分隔流

在具有GNU或现代BSD扩展(包括MacOS X)的系统上,您可以(并且应该)NUL分隔find的输出:

find . -type f -print0 | xargs -0 shasum --

使用find -exec

也就是说,你可以通过完全符合现代(~2006)POSIX的方式将xargs完全取出来做得更好:

find . -type f -exec shasum -- '{}' +

请注意,--参数指定shasum以后所有参数都是文件名。如果您使用find * -type f ...,那么您可以使用短划线开始结果;使用--可确保此结果不会被解释为一组选项。

使用换行符分隔符(及其安全风险)

如果您有GNU xargs,但不要可以选择NUL分隔的输入流,那么xargs -d $'\n'(在shell中,例如带有ksh扩展名的bash)将会避免引用和转义行为:

xargs -d $'\n' shasum -- <files.txt

然而,这不是最理想的,因为换行文字实际上可能在文件名中,因此无法区分分隔两个名称的换行符和作为实际名称一部分的换行符。请考虑以下情形:

mkdir -p ./file.txt$'\n'/etc/passwd$'\n'/
touch ./file.txt$'\n'/etc/passwd$'\n'file.txt file.txt
find . -type f | xargs -d $'\n' shasum --

这将具有类似于以下内容的输出:

da39a3ee5e6b4b0d3255bfef95601890afd80709  ./file.txt
da39a3ee5e6b4b0d3255bfef95601890afd80709  ./file.txt
c0c71bac843a3ec7233e99e123888beb6da8fbcf  /etc/passwd
da39a3ee5e6b4b0d3255bfef95601890afd80709  file.txt

...因此允许可以控制文件名的攻击者为任意文件外部导致shasum将目标结构添加到您的输出中。