如何递归删除某种类型的文件

时间:2014-08-25 07:45:33

标签: regex sed find

我误读了gzip文档,现在我必须删除大量的" .gz"来自许多目录的文件。我尝试使用' find'找到所有.gz文件。但是,只要名称中有空格的文件,rm就会将其解释为另一个文件。只要有短划线,rm就会将其解释为新旗帜。我决定使用' sed'用" \"替换空格和#34; \ - "的空格划线,以及我的想法。

find . -type f -name '*.gz' | sed -r 's/\ /\\ /g' | sed -r 's/\ -/ \\-/g'

当我在一个文件上运行find / sed查询时,例如,其名称为" Test - File - for - show.gz",我得到输出

./Test\ \-\ File\ \-\ for\ \-\ show.gz

rm似乎可以接受,但是当我运行时

rm $(find . -type f -name '*.gz'...)

我得到了

rm: cannot remove './Test\\': No such file or directory
rm: cannot remove '\\-\\': No such file or directory
rm: cannot remove 'File\\': No such file or directory
rm: cannot remove '\\-\\': No such file or directory
...

我没有广泛使用sed,所以我不得不假设我对正则表达式做错了。如果你知道我做错了什么,或者你有更好的解决方案,请告诉我。

2 个答案:

答案 0 :(得分:8)

在空格之前添加反斜杠可以保护空间免受shell源代码中的扩展。但是命令替换中的命令输出不进行shell解析,只进行通配符扩展和字段拆分。在空格之前添加反斜杠不会保护它们免受字段拆分。

在破折号之前添加反斜杠完全没用,因为rm将破折号解释为特殊符号,并且它不会将反斜杠解释为特殊。

find的输出通常不明确 - 文件名可以包含换行符,因此您不能使用换行符作为文件名分隔符。解析find的输出通常会被破坏,除非您处理已知的受限字符集中的文件名,并且它通常不是最简单的方法。

find具有执行外部程序的内置方式:-exec操作。没有进行解析,因此文件名中的特殊字符不会出现任何问题。 (以-开头的路径仍然可以解释为一个选项,但所有路径都以.开头,因为那是遍历的目录。)

find . -type f -name '*.gz' -exec rm {} +

许多find实现(Linux,Cygwin,BSD)可以在不调用外部实用程序的情况下删除文件:

find . -type f -name '*.gz' -delete

有关编写健壮的shell脚本的更多信息,请参阅Why does my shell script choke on whitespace or other special characters?

答案 1 :(得分:1)

无需管道输入sed等。您可以使用-exec上的find标志,它允许您对每个结果执行命令。命令。

例如,对于您的情况,这将起作用:

find . -type f -name '*.gz' -exec rm {} \;

与:

大致相同
find . -type f -name '*.gz' -exec rm {} +

最后一个没有打开每个结果的子shell,这使得它更快。


来自man find

  

-exec command;

     

执行命令;如果返回0状态,则返回true。以下全部   查找的参数被认为是命令的参数,直到   由;' is encountered. The string {}'组成的参数是   由当前正在处理的文件名替换   在命令的参数中,而不仅仅是在参数中   单独,如某些版本的查找。这两种结构都是如此   可能需要转义(使用“\”)或引用以保护它们   由shell扩展。有关示例,请参见“示例”部分   使用-exec选项。指定的命令运行一次   每个匹配的文件。该命令在起始目录中执行。   使用-exec时存在不可避免的安全问题   行动;你应该使用-execdir选项。