// gipsa @ C066 on 2012-02-26
// update: 2014-07-17
用find 递归删除目录时报错及解决
将svn 代码发布到生产环境时可能需要将所有 .svn 目录删除。
尝试使用:
find trunk -type d -name '.svn' -exec rm -rf {} \;
执行之后,所有的.svn目录都被删除,但是find也给出了一堆报错信息:
类似:
find: `./trunk/knowledge/.svn': No such file or directory
find: `./trunk/.svn': No such file or directory
find: `./trunk/data_contrast/.svn': No such file or directory
所有被删除的目录都报了一次。
原因:
find 是递归查找。
当-exec 的参数以分号(;)结尾时,每次遇到一个匹配的文件,都会立即调用一次command。
find要递归进入某目录之前,该目录已经被删除了的情况。
于是find 报出如前所述的提示信息。
解决方案0:
参考手册,-exec 的参数以加号(+)结尾。
find trunk -type d -name '.svn' -exec rm -rf {} +
这会将所有要删除的文件放到一起,最后统一传递给command并执行之。
详见下附手册摘译。
解决方案1:
借助 xargs
find trunk -type d -name '.svn' | xargs rm -rf
解决方案2:
for i in `find trunk -type d -name '.svn' `; do
rm -rf $i
done
解决方案3:
在传递代码到机器上时,借助其他工具过滤掉.svn目录,如 rsync 的 --exclude 选项。
附 find 手册摘译:
-exec command ;
Execute command; true if 0 status is returned.
All following arguments to find are taken to be arguments to the command
until an argument consisting of `;' is encountered.
The string `{}' is replaced by the current file name being processed
everywhere it occurs in the arguments to the command, not just in
arguments where it is alone, as in some versions of find.
Both of these constructions might need to be escaped (with a `\') or
quoted to protect them from expansion by the shell.
See the EXAMPLES section for examples of the use of the -exec option.
The specified command is run once for each matched file.
The command is executed in the starting directory.
There are unavoidable security problems surrounding use of the -exec action;
you should use the -execdir option instead.
执行 command; 如果command返回0则为真。
后面所有传给find的参数都将作为command的参数,直到遇到一个含有分号的参数。
字符串 {} 将被替换为当前文件名, not just in arguments where it is alone(?)。
这两个结构(?)都可能需要用反斜线转义或者用引号包围来防止它们被shell展开。
参见 EXAMPLES 部分的示例来了解 -exec 选项的用法。
指定的命令在每个匹配的file上只执行一次。
命令在起始目录执行。
围绕使用-exec有一些无法避免的安全问题;你应该使用 -execdir 选项来替代。(!!)
-exec command {} +
This variant of the -exec action runs the specified command on the selected files,
but the command line is built by appending each selected file name at the end;
the total number of invocations of the command will be much less than the number of matched files.
The command line is built in much the same way that xargs builds its command lines.
Only one instance of `{}' is allowed within the command. The command is executed in the starting directory.
-exec 的这个变种在选中的文件上执行指定的命令,但是命令行是通过将每一个被选中的文件附加到最后来构建的;
命令的总调用次数将比匹配的文件的数目少很多。
这里命令行的构建方式很xargs构建其命令行的方法很像。
命令内部只能出现一次 {}。
命令在起始目录执行。
-execdir command ;
-execdir command {} +
Like -exec, but the specified command is run from the subdirectory containing the
matched file, which is not normally the directory in which you started find.
This a much more secure method for invoking commands, as it avoids race
conditions during resolution of the paths to the matched files.
As with the -exec action, the `+' form of -execdir will build a command line
to process more than one matched file, but any given invocation of command
will only list files that exist in the same subdirectory.
If you use this option, you must ensure that your $PATH environment variable
does not reference `.'; otherwise, an attacker can run any commands they like
by leaving an appropriately-named file in a directory in which you will run -execdir.
The same applies to having entries in $PATH which are empty or which are not absolute directory names.
和 -exec 相似,但是指定的命令将在包含匹配文件的子目录中执行,这通常不是你启动find的目录。
这是一种安全得多的调用命令的方式,因为这样避免了解析匹配文件的路径时的竞态。
和-exec 一样,-execdir的+模式将构建一个命令行来处理多个匹配的文件。
但是每次命令的调用都只会列出存在于同一个子目录下的文件。(?)
如果你使用这个选项,你必须确保你的 $PATH 环境变量中没有引用 . 。
否则,攻击者可以通过在你将要执行 -execdir 的目录中
留下一个 刻意命名的文件,从而执行任意命令。
当你的 $PATH 中有 empty路径 或者相对路径时。同样的情形会出现(指前述被攻击风险,译者注)。