Linux 删除不包含特定字符串的文件

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11280389/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 07:11:22  来源:igfitidea点击:

Remove files not containing a specific string

linuxbashsedgrep

提问by Hakim

I want to find the files not containing a specific string (in a directory and its sub-directories) and remove those files. How I can do this?

我想找到不包含特定字符串的文件(在目录及其子目录中)并删除这些文件。我怎么能做到这一点?

回答by Ian Macalinao

One possibility is

一种可能性是

find . -type f '!' -exec grep -q "my string" {} \; -exec echo rm {} \;

You can remove the echoif the output of this preview looks correct.

echo如果此预览的输出看起来正确,您可以删除。

The equivalent with -deleteis

与等效-deleteIS

find . -type f '!' -exec grep -q "user_id" {} \; -delete

find . -type f '!' -exec grep -q "user_id" {} \; -delete

but then you don't get the nice preview option.

但是这样你就没有很好的预览选项。

回答by rodion

EDIT:This is how you SHOULD NOTdo this! Reason is given here. Thanks to @ormaaj for pointing it out!

编辑:这是你不应该这样做的方式!原因在这里给出。感谢@ormaaj 指出!

find . -type f | grep -v "exclude string" | xargs rm

Note: greppattern will match against full file path from current directory (see find . -type foutput)

注意:grep模式将与当前目录的完整文件路径匹配(见find . -type f输出)

回答by ormaaj

GNU grep and bash.

GNU grep 和 bash。

grep -rLZ "$str" . | while IFS= read -rd '' x; do rm "$x"; done

Use a findsolution if portability is needed. This is slightly faster.

find如果需要便携性,请使用解决方案。这稍微快一点。

回答by Alan Curry

I can think of a few ways to approach this. Here's one: find and grep to generate a list of files with no match, and then xargs rm them.

我可以想到几种方法来解决这个问题。这是一个: find 和 grep 生成不匹配的文件列表,然后 xargs rm 它们。

find yourdir -type f -exec grep -F -L 'yourstring' '{}' + | xargs -d '\n' rm

This assumes GNU tools (grep -L and xargs -d are non-portable) and of course no filenames with newlines in them. It has the advantage of not running grep and rm once per file, so it'll be reasonably fast. I recommend testing it with "echo" in place of "rm" just to make sure it picks the right files before you unleash the destruction.

这假设 GNU 工具(grep -L 和 xargs -d 是不可移植的)并且当然没有包含换行符的文件名。它的优点是不对每个文件运行 grep 和 rm 一次,因此速度相当快。我建议用“echo”代替“rm”来测试它,以确保它在你释放破坏之前选择正确的文件。

回答by Nick

The following will work:

以下将起作用:

find . -type f -print0 | xargs --null grep -Z -L 'my string' | xargs --null rm

This will firstly use find to print the names of all the files in the current directory and any subdirectories. These names are printed with a null terminator rather than the usual newline separator (try piping the output to od -cto see the effect of the -print0argument.

这将首先使用 find 打印当前目录和任何子目录中所有文件的名称。这些名称用空终止符打印,而不是通常的换行符(尝试将输出传送od -c到以查看-print0参数的效果。

Then the --nullparameter to xargstells it to accept null-terminated inputs. xargswill then call grepon a list of filenames.

然后--null参数 toxargs告诉它接受以空字符结尾的输入。xargs然后将调用grep文件名列表。

The -Zargument to grepworks like the -print0argument to find, so grep will print out its results null-terminated (which is why the final call to xargsneeds a --nulloption too). The -Largument to grepcauses grepto print the filenames of those files on its command line (that xargshas added) which don'tmatch the regular expression:

-Zto的参数与 togrep-print0参数类似find,因此 grep 将打印出以空字符结尾的结果(这就是为什么最终调用 to 也xargs需要一个--null选项)。的-L参数grep导致grep在其命令行(xargs已添加)上打印与正则表达式匹配的那些文件的文件名:

my string

我的字符串

If you want simple matching without regular expression magic then add the -Foption. If you want more powerful regular expressions then give a -Eargument. It's a good habit to use single quotes rather than double quotes as this protects you against any shell magic being applied to the string (such as variable substitution)

如果您想要没有正则表达式魔法的简单匹配,请添加该-F选项。如果你想要更强大的正则表达式,那就给出一个-E论点。使用单引号而不是双引号是一个好习惯,因为这可以保护您免受应用于字符串的任何 shell 魔法(例如变量替换)

Finally you call xargsagain to get rid of all the files that you've found with the previous calls.

最后,您xargs再次调用以删除您在先前调用中找到的所有文件。

The problem with calling grepdirectly from the findcommand with the -execargument is that grepthen gets invoked once per file rather than once for a whole batch of files as xargsdoes. This is muchfaster if you have lots of files. Also don't be tempted to do stuff like:

grep直接从find带有-exec参数的命令调用的问题在于,grep每个文件都会调用一次,而不是像xargs这样对整批文件调用一次。这是快,如果你有大量的文件。也不要试图做这样的事情:

rm $(some command that produces lots of filenames)

It's always better to pass it to xargsas this knows the maximum command-line limits and will call rmmultiple times each time with as many arguments as it can.

最好将它传递给它,xargs因为它知道最大命令行限制,并且rm每次都会使用尽可能多的参数调用多次。

Note that this solution would have been simpler without the need to cope with files containing white space and new lines.

请注意,此解决方案会更简单,而无需处理包含空格和新行的文件。

Alternatively

或者

grep -r -L -Z 'my string' . | xargs --null rm

will work too (and is shorter). The -rargument to grepcauses it to read all files in the directory and recursively descend into any subdirectories). Use the find ...approach if you want to do some other tests on the files as well (such as age or permissions).

也会起作用(并且更短)。在-r对参数grep使其读取目录中的所有文件和递归下降到任何子目录)。find ...如果您还想对文件进行一些其他测试(例如年龄或权限),请使用该方法。

Note that any of the single letter arguments, with a single dash introducer, can be grouped together (for instance as -rLZ). But note also that finddoes not use the same conventions and has multi-letter arguments introduced with a single dash. This is for historical reasons and hasn't ever been fixed because it would have broken too many scripts.

请注意,任何带有单个破折号介绍符的单字母参数都可以组合在一起(例如作为-rLZ)。但还要注意,find它不使用相同的约定,并且使用单个破折号引入了多字母参数。这是出于历史原因,从未修复过,因为它会破坏太多脚本。

回答by estebancod

To remove files not containing a specific string:

要删除不包含特定字符串的文件:

Bash:

重击:

To use them, enable the extglob shell option as follows:

要使用它们,请按如下方式启用 extglob shell 选项:

shopt -s extglob

And just remove all files that don't have the string "fix":

只需删除所有没有字符串“fix”的文件:

rm !(*fix*)

If you want to don't delete all the files that don't have the names "fix" and "class":

如果您不想删除所有没有名称“fix”和“class”的文件:

rm !(*fix*|*class*)

Zsh:

Zsh:

To use them, enable the extended glob zsh shell option as follows:

要使用它们,请启用扩展的 glob zsh shell 选项,如下所示:

setopt extended_glob

Remove all files that don't have the string, in this example "fix":

删除所有没有字符串的文件,在本例中为“修复”:

rm -- ^*fix*

If you want to don't delete all the files that don't have the names "fix" and "class":

如果您不想删除所有没有名称“fix”和“class”的文件:

rm -- ^(*fix*|*class*)

It's possible to use it for extensions, you only need to change the regex: (.zip) , (.doc), etc.

可以将它用于扩展,您只需要更改正则表达式:( .zip) 、(.doc) 等。

Here are the sources:

以下是来源:

https://www.tecmint.com/delete-all-files-in-directory-except-one-few-file-extensions/

https://www.tecmint.com/delete-all-files-in-directory-except-one-few-file-extensions/

https://codeday.me/es/qa/20190819/1296122.html

https://codeday.me/es/qa/20190819/1296122.html