从 findutils 的手册中得知xargs
在许多应用程序中,如果 xargs 由于文件名包含特殊字符而无法处理文件,则可能会丢失一些数据。
然而,这是使用空白分隔名称可能导致的问题的一个极端示例。如果每天从 cron 运行以下命令,则任何用户都可以删除系统上的任何文件:
find / -name ’#*’ -atime +7 -print | xargs rm
例如,你可以这样做:
eg$ echo > ’# vmunix’
然后是计划任务将删除 /vmunix,如果它以 / 作为当前目录运行 xargs。
到删除其他文件,例如 /u/joeuser/.plan,您可以这样做:
eg$ mkdir ’# ’ eg$ cd ’# ’ eg$ mkdir u u/joeuser u/joeuser/.plan’ ’ eg$ echo > u/joeuser/.plan’ /#foo’ eg$ cd .. eg$ find . -name ’#*’ -print | xargs echo ./# ./# /u/joeuser/.plan /#foo
在上面的例子中,如何xargs
处理提供的文件名find
,以及如何删除文件?
谢谢。
答案1
问题在于如何xargs
读取输入并将其传递给命令。
我们可以很容易地看到这一点rm -i
$ touch a 'b c' 'd
> e'
$ find -type f | cat
./d
e
./b c
./a
$ find -type f | xargs rm -i
rm: cannot remove './d': No such file or directory
rm: cannot remove 'e': No such file or directory
rm: cannot remove './b': No such file or directory
rm: cannot remove 'c': No such file or directory
rm: remove regular empty file './a'? $
请注意,我们尝试删除 5 个文件;./a
,./b
,c
,./d
, 和e
因此,文件名中的空格和换行符都会导致两个参数传递给命令。
标准解决方案是使用find -print0
和xargs -0
$ find -type f -print0 | xargs -0 rm -i
rm: cannot remove '.': Is a directory
rm: remove regular empty file './d\ne'?
rm: remove regular empty file './b c'?
rm: remove regular empty file './a'? $
现在,NUL 字符(不能是文件名的一部分)用作分隔符,并且空格不重要。
答案2
问题的另一半是如何应对。答案是使用\0
定界而不是空格定界(-0
在文件名中不允许使用,它是唯一不允许的字符。/
是文件名的一部分,但有特殊用途)。
为此,请按如下方式更改代码。
find … -print0 | xargs -0 …