[英]Remove files not containing a specific string
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?
我该怎么做?
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.这将首先使用 find 打印当前目录和任何子目录中所有文件的名称。 These names are printed with a null terminator rather than the usual newline separator (try piping the output to
od -c
to see the effect of the -print0
argument.这些名称用空终止符打印,而不是通常的换行符(尝试将输出传送到
od -c
以查看-print0
参数的效果。
Then the --null
parameter to xargs
tells it to accept null-terminated inputs.然后
xargs
的--null
参数告诉它接受以 null 结尾的输入。 xargs
will then call grep
on a list of filenames.然后
xargs
将对文件名列表调用grep
。
The -Z
argument to grep
works like the -print0
argument to find
, so grep will print out its results null-terminated (which is why the final call to xargs
needs a --null
option too).该
-Z
参数grep
作品像-print0
参数find
,这样的grep会打印出它的结果空值终止的(这就是为什么到最后调用xargs
需要--null
选项也是如此)。 The -L
argument to grep
causes grep
to print the filenames of those files on its command line (that xargs
has added) which don't match the regular expression: grep
的-L
参数导致grep
在其命令行上打印那些与正则表达式不匹配的文件的文件名( xargs
已添加):
my string
我的字符串
If you want simple matching without regular expression magic then add the -F
option.如果您想要没有正则表达式魔法的简单匹配,请添加
-F
选项。 If you want more powerful regular expressions then give a -E
argument.如果你想要更强大的正则表达式,那么给一个
-E
参数。 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)使用单引号而不是双引号是一个好习惯,因为这可以保护您免受应用于字符串的任何 shell 魔法(例如变量替换)
Finally you call xargs
again to get rid of all the files that you've found with the previous calls.最后,您再次调用
xargs
以删除您在先前调用中找到的所有文件。
The problem with calling grep
directly from the find
command with the -exec
argument is that grep
then gets invoked once per file rather than once for a whole batch of files as xargs
does.直接从带有
-exec
参数的find
命令调用grep
的问题在于, grep
然后每个文件被调用一次,而不是像xargs
那样对整批文件调用一次。 This is much faster if you have lots of files.这是更快,如果你有大量的文件。 Also don't be tempted to do stuff like:
也不要试图做这样的事情:
rm $(some command that produces lots of filenames)
It's always better to pass it to xargs
as this knows the maximum command-line limits and will call rm
multiple 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
-r
argument to grep
causes it to read all files in the directory and recursively descend into any subdirectories). grep
的-r
参数使其读取目录中的所有文件并递归下降到任何子目录)。 Use the find ...
approach if you want to do some other tests on the files as well (such as age or permissions).如果您还想对文件进行一些其他测试(例如年龄或权限),请使用
find ...
方法。
Note that any of the single letter arguments, with a single dash introducer, can be grouped together (for instance as -rLZ
).请注意,任何带有单个破折号介绍
-rLZ
的单字母参数都可以组合在一起(例如-rLZ
)。 But note also that find
does not use the same conventions and has multi-letter arguments introduced with a single dash.但还要注意
find
不使用相同的约定,并且使用单个破折号引入了多字母参数。 This is for historical reasons and hasn't ever been fixed because it would have broken too many scripts.这是出于历史原因,从未修复过,因为它会破坏太多脚本。
GNU grep and bash. GNU grep 和 bash。
grep -rLZ "$str" . | while IFS= read -rd '' x; do rm "$x"; done
Use a find
solution if portability is needed.如果需要可移植性,请使用
find
解决方案。 This is slightly faster.这稍微快一点。
EDIT: This is how you SHOULD NOT do this!编辑:这是你不应该这样做的方式! Reason is given here .
原因在这里给出。 Thanks to @ormaaj for pointing it out!
感谢@ormaaj 指出!
find . -type f | grep -v "exclude string" | xargs rm
Note: grep
pattern will match against full file path from current directory (see find . -type f
output)注意:
grep
模式将匹配当前目录中的完整文件路径(请参阅find . -type f
输出)
One possibility is一种可能性是
find . -type f '!' -exec grep -q "my string" {} \; -exec echo rm {} \;
You can remove the echo
if the output of this preview looks correct.如果此预览的输出看起来正确,您可以删除
echo
。
The equivalent with -delete
is与
-delete
等效的是
find . -type f '!' -exec grep -q "user_id" {} \\; -delete
but then you don't get the nice preview option.但是这样你就没有很好的预览选项。
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.这假设 GNU 工具(grep -L 和 xargs -d 是不可移植的)并且当然没有包含换行符的文件名。 It has the advantage of not running grep and rm once per file, so it'll be reasonably fast.
它的优点是不对每个文件运行 grep 和 rm 一次,因此速度相当快。 I recommend testing it with "echo" in place of "rm" just to make sure it picks the right files before you unleash the destruction.
我建议用“echo”代替“rm”来测试它,以确保它在你释放破坏之前选择正确的文件。
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
This worked for me, you can remove the -f if you're okay with deleting directories.这对我有用,如果您可以删除目录,则可以删除 -f。
myString="keepThis"
for x in `find ./`
do if [[ -f $x && ! $x =~ $myString ]]
then rm $x
fi
done
Another solution (although not as fast).另一种解决方案(虽然没有那么快)。 The top solution didn't work in my case because the string I needed to use in place of 'my string' has special characters.
最佳解决方案在我的案例中不起作用,因为我需要用来代替“我的字符串”的字符串具有特殊字符。
find -type f ! -name "*my string*" -exec rm {} \; -print
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.