[英]How to Recursively Remove Files of a Certain Type
我误读了gzip文档,现在我必须从许多目录中删除大量的“.gz”文件。 我尝试使用'find'来查找所有.gz文件。 但是,只要名称中有空格的文件,rm就会将其解释为另一个文件。 只要有破折号,rm就会将其解释为新旗帜。 我决定用'sed'用“\\”代替空格,用空格破坏用“\\ - ”代替,这就是我想出来的。
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,所以我不得不假设我在使用正则表达式做错了。 如果你知道我做错了什么,或者你有更好的解决方案,请告诉我。
在空格之前添加反斜杠可以保护空间免受shell源代码中的扩展。 但是命令替换中的命令输出不进行shell解析,只进行通配符扩展和字段拆分。 在空格之前添加反斜杠不会保护它们免受字段拆分。
在破折号之前添加反斜杠是完全无用的,因为它是将破折号解释为特殊的rm
,并且它不会将反斜杠解释为特殊的。
find
的输出通常是不明确的 - 文件名可以包含换行符,因此您不能使用换行符作为文件名分隔符。 除非你在一个已知的,受限制的字符集中处理文件名,否则解析find
的输出通常会被破坏,而且它通常不是最简单的方法。
find
有一个内置的方法来执行外部程序: -exec
action。 没有进行解析,因此文件名中的特殊字符不会出现任何问题。 (以-
开头的路径仍然可以解释为一个选项,但所有路径都以.
开头.
因为那是遍历的目录。)
find . -type f -name '*.gz' -exec rm {} +
许多find
实现(Linux,Cygwin,BSD)可以在不调用外部实用程序的情况下删除文件:
find . -type f -name '*.gz' -delete
请参阅为什么我的shell脚本会在空格或其他特殊字符上出现问题? 有关编写健壮的shell脚本的更多信息。
没有必要管道到sed等。相反,你可以在find
上使用-exec
标志,它允许你对命令的每一个结果执行一个命令。
例如,对于您的情况,这将工作:
find . -type f -name '*.gz' -exec rm {} \;
大致相同:
find . -type f -name '*.gz' -exec rm {} +
最后一个没有为每个结果打开子shell,这使得它更快。
从man find
:
-exec命令;
执行命令; 如果返回0状态,则返回true。 以下所有要查找的参数都被视为命令的参数,直到参数组成为
;' is encountered. The string
;' is encountered. The string
;' is encountered. The string
{}'被在命令参数中出现的任何位置处理的当前文件名替换,而不仅仅是在某些版本的find中的参数中。 这两种结构都可能需要进行转义(使用“\\”)或引用以保护它们不被shell扩展。 有关使用-exec选项的示例,请参阅“示例”部分。 为每个匹配的文件运行一次指定的命令。 该命令在起始目录中执行。 围绕使用-exec操作存在不可避免的安全问题; 你应该使用-execdir选项。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.