우리는 많은 수의 파일(5백만 개 이상)을 포함하는 SAN을 보유하고 있습니다. 개발자 스크립트의 이상한 오류로 인해 일부 파일이 삭제되었으며 이제 어떤 파일이 삭제되었는지 파악해야 합니다.
이제 다음과 같이 확인해야 할 파일 이름 목록(데이터베이스에서)이 있습니다.
49
50
51
52
find
다음과 같은 명령을 사용하여 단일 파일과 여러 파일에 대해 이 작업을 수행하는 방법을 알아냈습니다 .
find /mnt/SAN/documents/ -type f -name"92441_1"
이 방법은 작동하지만 이 명령을 사용하여 200,000개가 넘는 파일을 확인할 수는 없습니다. 그래서 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
가장 간단한 방법은 쉘 루프를 사용하여 파일에서 파일 이름을 읽은 다음 find
백그라운드에서 여러 명령을 실행하는 것입니다.
while IFS= read -r file; do
find /mnt/SAN/documents/ -type f -name "$file" &
done < fileList.txt > foundFiles.txt
그러나 이렇게 하면 200,000개가 넘는 인스턴스가 시작되고 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
200,000개가 넘는 파일의 모든 파일 이름에 대해 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 루프에서 변수 이름을 수정하고 싶을 수도 있지만 제 생각의 요지는 이해하신 것 같습니다.