200,000개 이상의 파일과 다른 이름의 출력을 찾는 방법

200,000개 이상의 파일과 다른 이름의 출력을 찾는 방법

우리는 많은 수의 파일(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.txtfound

답변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 루프에서 변수 이름을 수정하고 싶을 수도 있지만 제 생각의 요지는 이해하신 것 같습니다.

관련 정보