简体   繁体   English

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

[英]How to Recursively Remove Files of a Certain Type

I misread the gzip documentation, and now I have to remove a ton of ".gz" files from many directories inside one another. 我误读了gzip文档,现在我必须从许多目录中删除大量的“.gz”文件。 I tried using 'find' to locate all .gz files. 我尝试使用'find'来查找所有.gz文件。 However, whenever there's a file with a space in the name, rm interprets that as another file. 但是,只要名称中有空格的文件,rm就会将其解释为另一个文件。 And whenever there's a dash, rm interprets that as a new flag. 只要有破折号,rm就会将其解释为新旗帜。 I decided to use 'sed' to replace the spaces with "\\ " and the space-dashes with "\\ -", and here's what I came up with. 我决定用'sed'用“\\”代替空格,用空格破坏用“\\ - ”代替,这就是我想出来的。

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

When I run the find/sed query on a file that, for example, has a name of "Test - File - for - show.gz", I get the output 当我在一个文件上运行find / sed查询时,例如,其名称为“Test - File - for - show.gz”,我得到了输出

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

Which appears to be acceptable for rm, but when I run 这对于rm来说似乎是可以接受的,但是当我跑步时

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

I get 我明白了

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
...

I haven't made extensive use of sed, so I have to assume I'm doing something wrong with the regular expressions. 我没有广泛使用sed,所以我不得不假设我在使用正则表达式做错了。 If you know what I'm doing wrong, or if you have a better solution, please tell me. 如果你知道我做错了什么,或者你有更好的解决方案,请告诉我。

Adding backslashes before spaces protects the spaces against expansion in shell source code. 在空格之前添加反斜杠可以保护空间免受shell源代码中的扩展。 But the output of a command in a command substitution does not undergo shell parsing, it only undergoes wildcard expansion and field splitting. 但是命令替换中的命令输出不进行shell解析,只进行通配符扩展和字段拆分。 Adding backslashes before spaces doesn't protect them against field splitting. 在空格之前添加反斜杠不会保护它们免受字段拆分。

Adding backslashes before dashes is completely useless since it's rm that interprets dashes as special, and it doesn't interpret backslashes as special. 在破折号之前添加反斜杠是完全无用的,因为它是将破折号解释为特殊的rm ,并且它不会将反斜杠解释为特殊的。

The output of find is ambiguous in general — file names can contain newlines, so you can't use a newline as a file name separator. find的输出通常是不明确的 - 文件名可以包含换行符,因此您不能使用换行符作为文件名分隔符。 Parsing the output of find is usually broken unless you're dealing with file names in a known, restricted character set, and it's often not the simplest method anyway. 除非你在一个已知的,受限制的字符集中处理文件名,否则解析find的输出通常会被破坏,而且它通常不是最简单的方法。

find has a built-in way to execute external programs: the -exec action. find有一个内置的方法来执行外部程序: -exec action。 There's no parsing going on, so this isn't subject to any problem with special characters in file names. 没有进行解析,因此文件名中的特殊字符不会出现任何问题。 (A path beginning with - could still be interpreted as an option, but all paths begin with . since that's the directory being traversed.) (以-开头的路径仍然可以解释为一个选项,但所有路径都以.开头.因为那是遍历的目录。)

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

Many find implementations (Linux, Cygwin, BSD) can delete files without invoking an external utility: 许多find实现(Linux,Cygwin,BSD)可以在不调用外部实用程序的情况下删除文件:

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

See Why does my shell script choke on whitespace or other special characters? 请参阅为什么我的shell脚本会在空格或其他特殊字符上出现问题? for more information on writing robust shell scripts. 有关编写健壮的shell脚本的更多信息。

There is no need to pipe to sed, etc. Instead, you can make use of the -exec flag on find , that allows you to execute a command on each one of the results of the command. 没有必要管道到sed等。相反,你可以在find上使用-exec标志,它允许你对命令的每一个结果执行一个命令。

For example, for your case this would work: 例如,对于您的情况,这将工作:

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

which is approximately the same as: 大致相同:

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

The last one does not open a subshell for each result, which makes it faster. 最后一个没有为每个结果打开子shell,这使得它更快。


From man find : man find

-exec command ; -exec命令;

Execute command; 执行命令; true if 0 status is returned. 如果返回0状态,则返回true。 All following arguments to find are taken to be arguments to the command until an argument consisting of ;' is encountered. The string 以下所有要查找的参数都被视为命令的参数,直到参数组成为;' is encountered. The string ;' is encountered. The string ;' 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. ;' is encountered. The string {}'被在命令参数中出现的任何位置处理的当前文件名替换,而不仅仅是在某些版本的find中的参数中。 Both of these constructions might need to be escaped (with a `\\') or quoted to protect them from expansion by the shell. 这两种结构都可能需要进行转义(使用“\\”)或引用以保护它们不被shell扩展。 See the EXAMPLES section for examples of the use of the -exec option. 有关使用-exec选项的示例,请参阅“示例”部分。 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; 围绕使用-exec操作存在不可避免的安全问题; you should use the -execdir option instead. 你应该使用-execdir选项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM