我想找到不包含特定字符串的文件(在目录及其子目录中)并删除这些文件。我怎么能做到这一点?
7 回答
以下将起作用:
find . -type f -print0 | xargs --null grep -Z -L 'my string' | xargs --null rm
这将首先使用 find 打印当前目录和任何子目录中所有文件的名称。这些名称使用空终止符而不是通常的换行符分隔符打印(尝试通过管道输出到od -c
以查看-print0
参数的效果。
然后--null
参数xargs
告诉它接受以空值结尾的输入。xargs
然后将调用grep
文件名列表。
-Z
参数的grep
工作方式与 的参数-print0
类似find
,因此 grep 将打印出以空值结尾的结果(这就是为什么最终调用也xargs
需要一个--null
选项的原因)。导致在其命令行(已添加)上打印与正则表达式不匹配的那些文件的文件名的参数-L
:grep
grep
xargs
我的弦
如果您想要没有正则表达式魔法的简单匹配,请添加该-F
选项。如果您想要更强大的正则表达式,请给出一个-E
论点。使用单引号而不是双引号是一个好习惯,因为这可以保护您免受任何应用于字符串的 shell 魔法(例如变量替换)
最后,您xargs
再次调用以删除您在先前调用中找到的所有文件。
grep
直接从带有参数的find
命令调用的问题是每个文件调用一次,而不是像整批文件那样调用一次。如果您有很多文件,这会快得多。也不要试图做类似的事情:-exec
grep
xargs
rm $(some command that produces lots of filenames)
最好将它传递给它,xargs
因为它知道最大命令行限制,并且rm
每次都会使用尽可能多的参数调用多次。
请注意,此解决方案会更简单,无需处理包含空格和新行的文件。
或者
grep -r -L -Z 'my string' . | xargs --null rm
也可以(而且更短)。-r
参数使其读取目录中的grep
所有文件并递归地下降到任何子目录)。find ...
如果您还想对文件进行一些其他测试(例如年龄或权限),请使用该方法。
请注意,任何带有单个破折号介绍器的单个字母参数都可以组合在一起(例如 as -rLZ
)。但还要注意,find
它不使用相同的约定,并且使用单个破折号引入了多字母参数。这是出于历史原因,并且从未修复过,因为它会破坏太多脚本。
GNU grep 和 bash。
grep -rLZ "$str" . | while IFS= read -rd '' x; do rm "$x"; done
find
如果需要可移植性,请使用解决方案。这稍微快一些。
编辑:这就是你不应该这样做的方式!原因在这里给出。感谢@ormaaj 指出!
find . -type f | grep -v "exclude string" | xargs rm
注意:grep
模式将匹配当前目录的完整文件路径(见find . -type f
输出)
一种可能是
find . -type f '!' -exec grep -q "my string" {} \; -exec echo rm {} \;
echo
如果此预览的输出看起来正确,您可以删除。
等价-delete
于
find . -type f '!' -exec grep -q "user_id" {} \; -delete
但是你没有得到很好的预览选项。
我可以想出几种方法来解决这个问题。这是一个: find 和 grep 生成一个不匹配的文件列表,然后 xargs rm 它们。
find yourdir -type f -exec grep -F -L 'yourstring' '{}' + | xargs -d '\n' rm
这假设 GNU 工具(grep -L 和 xargs -d 是不可移植的),当然没有包含换行符的文件名。它的优点是每个文件不运行 grep 和 rm 一次,所以它会相当快。我建议使用“echo”代替“rm”对其进行测试,以确保它在释放破坏之前选择正确的文件。
要删除不包含特定字符串的文件:
重击:
要使用它们,请启用 extglob shell 选项,如下所示:
shopt -s extglob
只需删除所有没有字符串“fix”的文件:
rm !(*fix*)
如果您不想删除所有没有名称“fix”和“class”的文件:
rm !(*fix*|*class*)
Zsh:
要使用它们,请启用扩展 glob zsh shell 选项,如下所示:
setopt extended_glob
删除所有没有字符串的文件,在本例中为“修复”:
rm -- ^*fix*
如果您不想删除所有没有名称“fix”和“class”的文件:
rm -- ^(*fix*|*class*)
可以将其用于扩展,您只需要更改正则表达式:(. zip)、( .doc)等。
以下是来源:
https://www.tecmint.com/delete-all-files-in-directory-except-one-few-file-extensions/
这对我有用,如果您可以删除目录,则可以删除 -f 。
myString="keepThis"
for x in `find ./`
do if [[ -f $x && ! $x =~ $myString ]]
then rm $x
fi
done