![Unix 使用 find 删除:删除文件中列出的所有文件](https://linux22.com/image/1395630/Unix%20%E4%BD%BF%E7%94%A8%20find%20%E5%88%A0%E9%99%A4%EF%BC%9A%E5%88%A0%E9%99%A4%E6%96%87%E4%BB%B6%E4%B8%AD%E5%88%97%E5%87%BA%E7%9A%84%E6%89%80%E6%9C%89%E6%96%87%E4%BB%B6.png)
在我的根目录中,我有几个文件夹,名为AA
、等,每个文件夹都包含格式为、等的文件。在我的根文件夹中,我还有一个文件BB
,其中有一堆用换行符分隔的文件名,看起来像这样:CC
AA1001.txt
BB1002.txt
all_to_delete
AA1004.txt
BB3004.txt
BB3005.txt ...
我现在想遍历根目录中的所有子目录并删除与给定文件名匹配的所有文件。到目前为止,我尝试过类似以下操作:
while read line; do find . -type f -name $line -exec rm -f {} \;; done
但是,这无法工作,因为已经while read line; do find . -type f -name $line; done
不匹配任何文件(因为 find 给出的输出为./AA/AA1001.txt
......)
你们有办法解决我这个问题吗?
答案1
给定一个包含文件名的文件,最简单的做法是逐行读取,然后将其传递给find
。但是,这将导致find
每个文件名都有一个单独的 实例,并且可能变成非常对于目录树中的大量文件列表和许多文件来说,速度很慢。
相反,我会做这样的事情:
find . -type f -name "*txt" | grep -wFf to_delete.txt | xargs -I{} rm '{}'
诀窍是将grep
文件作为要搜索的模式列表 ( -f
)。这-F
将确保您的文件名被视为字符串而不是正则表达式,这样您的文件名就不能包含特殊字符,如*
或[
或|
。然后您传递给xargs
并使用引 '{}'
,否则会因空白而无法删除文件。
笔记:这假设您的文件名都是唯一的,一个名称不能包含在另一个名称中。例如,您没有名为foo
和 的文件foobar
。如果有,给定一个模式foo
,这将删除这两个文件。要避免这种情况,请使用:
while IFS= read -r line; do find . -name "$line" -delete; done < to_delete.txt
从man find
:
-delete
Delete files; true if removal succeeded.
答案2
您对问题的描述有多直白?目录名都是两个字符吗?文件是否BB3004.txt
始终位于目录中BB
?如果是,则不需要find
;只需从文件名的前两个字符中提取目录名:
while read -r line
do
dir=$(expr "$line" : '\(..\)')
echo rm "$dir/$line"
rm "$dir/$line"
done < all_to_delete
答案3
有很多不同的方法可以实现这一点,但我将按照以下方式操作:
创建了一个包含几个文件的测试目录:
% ls ./teste
lala lele lolo lulu
创建了一个文件,列出了我想要删除的文件:
% cat to_delete.txt
lele
lolo
lulu
在这里我循环遍历“to_delete.txt”文件的每一行,将文件名传递给 find 命令,然后最终删除它们:
% while read filename; do find ./teste -name ${filename} -print0 | xargs -0 rm -vf; done < to_delete.txt
removed `./teste/lele'
removed `./teste/lolo'
removed `./teste/lulu'
完毕:
% ls ./teste
lala