`xargs` 如何处理 `find` 提供的文件名,这可能会导致问题?

`xargs` 如何处理 `find` 提供的文件名,这可能会导致问题?

从 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./bc./d, 和e

因此,文件名中的空格和换行符都会导致两个参数传递给命令。

标准解决方案是使用find -print0xargs -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 …

相关内容