我们有一个包含大量(超过 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.txt
found
答案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 循环中的变量名称,但我认为您已经了解了我的想法的要点。