我如何找到超过 200K 个不同名称的文件和输出

我如何找到超过 200K 个不同名称的文件和输出

我们有一个包含大量(超过 500 万个)文件的 SAN。由于开发人员脚本中出现一些奇怪的错误,一些文件已被删除,我们现在必须弄清楚哪些文件被删除。

现在,我确实有一个包含需要检查的文件名(来自我们的数据库)的列表,如下所示:

49
50
51
52

我已经弄清楚如何使用该find命令对单个和多个文件执行此操作,如下所示:

find /mnt/SAN/documents/ -type f -name"92441_1"

这可行,但我无法使用此命令来检查超过 200K+ 个文件。所以我想知道是否有人知道如何获取find从我的文件中获取输入的命令,或者是否有另一个命令可以用来完成此操作。

答案1

我会做类似的事情(假设使用 GNU 工具):

find /mnt/SAN/documents -type f -print0 | awk -F / '
  NR == FNR{check[$0]; next}
  $NF in check {print "found:", $0; delete check[$NF]}
  END {
    for (i in check)
      print "Not found:", i
  }' filename.list RS='\0' -

这将在filename.list.

或者报告所有发生的情况:

find /mnt/SAN/documents -type f -print0 | awk -F / '
  NR == FNR{check[$0]; notfound[$0]; next}
  $NF in check {print "found:", $0; delete notfound[$NF]}
  END {
    for (i in notfound)
      print "Not found:", i
  }' filename.list RS='\0' -

答案2

使用类似的东西

find /mnt/SAN/documents/ -type f | perl -ple 's,^.*/,,' > files_currently_present

生成当前在光盘上的文件列表,不带路径,然后使用

comm -2 -3 filelist_from database files_currently_present

将其与备份中的列表进行比较并生成消息文件列表。

答案3

最简单的方法是使用 shell 循环从文件中读取文件名,然后find在后台运行多个命令:

while IFS= read -r file; do
    find /mnt/SAN/documents/ -type f -name "$file" &
done < fileList.txt > foundFiles.txt

然而,这将启动 200K 以上的实例,find并且可能会让您的机器瘫痪。更好的方法是构建一个复杂的find命令,为其指定每个文件名:

$ printf 'find /mnt/SAN/documents/ -type f '; while IFS= read -r file; do printf -- '-name "%s" -o ' "$file"; done < fileList.txt | sed 's/-o $/\n/'
find /mnt/SAN/documents/ -type f -name "49" -o -name "50" -o -name "51" -o -name "52" 

然后,您可以通过复制/粘贴或使用以下命令来运行命令本身:

eval $(printf 'find /mnt/SAN/documents/ -type f '; \
    while IFS= read -r file; do 
        printf -- '-name "%s" -o ' "$file"; done < fileList.txt | 
            sed 's/-o $/\n/')

但是,如果文件太多,这也会中断,因此您需要批量运行它:

for i in $(seq 1 100 $(wc -l < fileList.txt)); do 
    k=$((i+100)); 
    printf 'find /mnt/SAN/documents/ -type f '; 
    sed -n "$i,${k}p" fileList.txt | 
    while IFS= read -r file; do 
        printf -- '-name "%s" -o ' "$file"; 
    done  | sed 's/-o $/\n/';   
done

find这将为列表中的每批 100 个文件创建单独的命令,您可以eval如上所示执行这些命令,或者只是保存在文件中并运行该文件:

for i in $(seq 1 100 $(wc -l < fileList.txt)); do 
    k=$((i+100)); 
    printf 'find /mnt/SAN/documents/ -type f '; 
    sed -n "$i,${k}p" fileList.txt | 
    while IFS= read -r file; do 
        printf -- '-name "%s" -o ' "$file"; 
    done  | sed 's/-o $/\n/';   
done > script.sh && bash script.sh > foundFiles.txt

注意斯蒂芬的方法,从现有文件开始并检查丢失的文件几乎肯定会更好(除非现有文件比丢失的文件多)。同样,您可以首先构建所有现有文件的列表,然后将comm其与目标文件列表进行比较(因为您说您有一个文件列表,所以我假设您的文件名永远不会包含换行符):

find /mnt/SAN/documents/ -type f | sort > found
comm -13 <(sort found) <(sort fileList.txt)

该命令将打印 中但不在 中的comm所有行。fileList.txtfound

答案4

对超过 200K 个文件中的每个文件名运行 find 非常耗时。如果我是你,我就会find ${FILESROOT} > /tmp/SANfiles逃跑

for filename in $(cat my_database_files)
do
  grep "${filename}" /tmp/SANfiles > /dev/null; r=${?}
  if [ ${r} -eq 0 ]
  then
    echo ${filename} >> /tmp/existing_files
  else
    echo ${filename} >> /tmp/missing_files
  fi
done

根据数据库中文件名的格式,您可能想要修改 for 循环中的变量名称,但我认为您已经了解了我的想法的要点。

相关内容