Bash - 删除大目录中的文件

Bash - Delete files in large directories

提问人:Batavia 提问时间:8/31/2023 最后编辑:Jason AllerBatavia 更新时间:9/6/2023 访问量:111

问:

我必须删除非常大的目录(500k 文件)中的文件,如下所示:

Fiche_8317.doc
Fiche_8318.doc
Fiche_8319.doc

我编写了一个循环来读取一个文件,该文件给了我必须删除的名称:*deletedFiles.txt

AAA;ZQ;00008319;2011-05-18;ACTA;RR02000354090127104747.doc
AAA;ZQ;00008320;2011-05-18;ACTA;RR02000354090127104747.doc
AAA;ZQ;00008321;2011-05-18;REDA;RR02000354090127104747.doc
AAA;ZQ;00008322;2011-05-18;ITAC;RR02000354090127104747.doc

我尝试了这样的循环(不是我的真实代码,我更改了变量):

while IFS=";" read -r idt surname
do  
    Echo $idt " " $surname
    #Supress leading 0 and delete
    find $DataPath/target/ -type f -name Fiche_"$((10#$idt))".* -delete
    
done < <(cut -d ";" -f 3,6 $DataPath/*deletedFiles.txt)

这段代码可以工作,但速度非常慢,在我的 Linux 服务器上每个文件超过 2 分钟。

目录中每个文件只有 1 个文件。idt

我可以改进一下吗? 我正在寻找一个更快的解决方案。

不幸的是,我只能使用 bash,因为我公司的调度程序只能与 bash 一起使用。

非常感谢

bash 性能 循环 delete-file

评论

0赞 DevSolar 8/31/2023
如果你能描述你的代码在做什么,或者更确切地说是需要做什么,而不是发布包含至少两个错别字的代码(即不是你正在运行的实际代码),那将会很有帮助......
3赞 DevSolar 9/1/2023
目录结构是扁平的,即所有文件都在 中,还是我们查看子目录?有没有办法限制您正在查看的子目录?你能编辑输入文件,所以“压制前导 0”已经完成吗?你真的需要这些文件吗,或者我们可以想出类似的东西吗?现在,你没有提供足够的信息来给出一个好的答案。.../target/findfindrm $DataPath/target/Fiche_${idt}.*
1赞 Mark Setchell 9/1/2023
请显示“deletedText”文件中的 4-5 行典型行以及因此被删除的相应文件的完整路径。
2赞 Gordon Davisson 9/1/2023
几乎可以肯定,重复运行是它运行缓慢的一个重要原因。所做的是扫描整个目录树,检查每个文件以查看它是否符合条件;在这种情况下,对于它找到并删除的每个文件,它还必须检查其他每个文件,确定其名称不匹配,然后忽略它(“这是它吗?“不”“是吗?”“不”......您希望某些内容直接转到正确的文件,而不必查看所有其他文件,或者只运行一次并让它在一次传递中找到要删除的所有文件。findfindfind
2赞 Mark Setchell 9/1/2023
如果你的文件被调用,它一定在当前目录下,所以没有必要使用,确定吗?您正在查找的目录中有多少个文件(大致),大致有多少个文件,粗略地删除多少个文件?您的调度程序启动的事实不会阻止您调用,也不会阻止您调用,就像您当前所做的那样。Fiche_8319.docfinddeletedFiles.txtbashPerlPythonfindcut

答:

1赞 Fravadona 9/1/2023 #1

花费大量时间的是遍历目录以查找要删除的文件。为了加快速度,您可以调用一次,使用 GNU 过滤文件路径并调用findawkrmxargs -0

find "$DataPath"/target -type f -print0 |
awk -v ORS='\0' '
    FNR == NR { prefixes[sprintf("Fiche_%d", $3)]; next }
    match($NF, /^[^.]+/) && (substr($NF,RSTART,RLENGTH) in prefixes)
' FS=';' "$DataPath"/deletedFiles.txt RS='\0' FS='/' - |
xargs -0 rm --
0赞 DevSolar 9/6/2023 #2

希望文件名中的星号是错别字:*deletedFiles

cut -d';' -f3 "$DataPath/deletedFiles.txt" | \
    sed "s/^0*\(.*\)/rm \"$DataPath/target/Fiche_\1.doc\"/" | \
    source /dev/stdin
  • cut -d';' -f3从输入中获取第三个字段。我从你的例子中删除了这句话,因为你正在寻找性能。echo

  • sed s/^0*\(.*\)/...从该字段中剥离前导零...

  • .../rm $DataPath/target/Fiche_\1.doc/...在命令、路径和前面附加 。rm.doc

  • source /dev/stdin从当前 shell 中的管道(命令序列)运行结果。(此功能在 bash v4.0 之前已出现错误。rm

如果您将多个文件放到一个命令行上以由单个文件删除,您可能会从中挤出更多的性能,但我不确定是否值得在性能和维护方面增加复杂性。rm