목록에서 누락된 파일을 찾는 방법은 무엇입니까?

목록에서 누락된 파일을 찾는 방법은 무엇입니까?

파일 목록이 있고 해당 파일이 내 파일 시스템에 있는지 확인하고 싶습니다. find다음과 같은 방법을 사용하여 이 작업을 수행 하고 싶습니다 .

for f in $(cat file_list); do
find . -name $f > /dev/null || print $f
done

(을 사용하여 ) 하지만 파일을 찾든 못 찾든 종료되기 zsh때문에 작동하지 않습니다 . 다른 테스트를 통해 출력이 생성되는지 테스트할 수 있다고 생각합니다 (거칠지만 효과적인 방법은 로 대체하는 것입니다 ) . 하지만 이는 트롤을 사용하여 염소를 잡는 것과 같은 느낌입니다(다른 국가에서는 큰 망치와 호두 문제에 대해 말할 수 있습니다).find0find> /dev/null|grep ''

find유용한 종료 값을 강제로 적용할 수 있는 방법이 있나요 ? 아니면 적어도 해당 파일 목록을 얻으십시오.아니요확립된? (어떤 영리한 논리적 연결 단어 선택을 사용하면 후자가 더 쉬울 수도 있다고 상상할 수 있지만, 그것을 알아내려고 할 때 항상 막히는 것 같습니다.)

배경/동기:"마스터" 백업이 있고 이를 삭제하기 전에(약간의 공간을 만들기 위해) 로컬 시스템의 특정 파일이 마스터 백업에 있는지 확인하고 싶습니다. 그래서 파일 목록을 만들어서 ssh호스트에 편집한 다음 누락된 파일을 찾는 가장 좋은 방법이 무엇인지 고민했습니다.

답변1

이를 사용하여 stat파일 시스템에 파일이 존재하는지 여부를 확인할 수 있습니다.

내장된 것을 사용해야 합니다.쉘 기능파일이 존재하는지 테스트합니다.

while read f; do
   test -f "$f" || echo $f
done < file_list

"테스트"는 선택 사항이며 스크립트는 실제로 그것 없이도 작동하지만 가독성을 위해 그대로 두었습니다.

편집하다:경로 없이 파일 이름 목록을 처리할 수밖에 없다면 find를 사용하여 파일 목록을 한 번 작성한 다음 grep을 사용하여 반복하여 그 안에 어떤 파일이 있는지 알아내는 것이 좋습니다.

find -type f /dst > $TMPFILE
while read f; do
    grep -q "/$f$" $TIMPFILE || echo $f
done < file_list

알아채다:

  • 파일 목록에는 디렉터리가 아닌 파일만 포함됩니다.
  • grep 일치 패턴의 슬래시는 부분 파일 이름이 아닌 전체 파일 이름을 비교하기 위한 것입니다.
  • 검색 패턴의 마지막 "$"는 줄 끝을 일치시키는 데 사용되므로 디렉터리 일치는 얻을 수 없고 전체 파일 이름 패치만 얻을 수 있습니다.

답변2

find성공적인 특수 사례가 발견되지 않은 것을 고려하십시오(오류가 발생하지 않음). 파일이 특정 조건을 충족하는지 테스트하는 일반적인 방법 find은 출력이 find비어 있는지 테스트하는 것입니다. 일치하는 파일이 존재할 때 효율성을 위해 -quitGNU find에서 사용하여 첫 번째 일치에서 종료하거나 head( head -c 1사용 가능한 경우 그렇지 않은 경우 head -n 1표준) 긴 출력을 생성하는 대신 깨진 파이프로 죽도록 다른 시스템에서 사용합니다.

while IFS= read -r name; do
  [ -n "$(find . -name "$name" -print | head -n 1)" ] || printf '%s\n' "$name"
done <file_list

bash ≥4 또는 zsh에서는 간단한 이름 일치를 위해 외부 명령이 필요하지 않습니다 . .thump 버전을 find사용할 수 있습니다 .**/$name

shopt -s nullglob
while IFS= read -r name; do
  set -- **/"$name"
  [ $# -ge 1 ] || printf '%s\n' "$name"
done <file_list

Zsh 버전의 원리는 비슷합니다.

while IFS= read -r name; do
  set -- **/"$name"(N)
  [ $# -ge 1 ] || print -- "$name"
done <file_list

아니면 패턴과 일치하는 파일이 존재하는지 테스트하는 더 짧지만 더 난해한 방법인가요? N일치하는 항목이 없으면 glob 한정자는 출력을 비우고 [1]첫 번째 일치 항목만 유지하며 일치하는 파일 이름 대신 e:REPLY=true:확장되도록 각 일치 항목을 변경합니다 . 1따라서 일치 항목이 있는지 또는 일치 항목이 없는지 여부 **/"$name"(Ne:REPLY=true:[1]) false로 확장됩니다 .true falsefalse

while IFS= read -r name; do
  **/"$name"(Ne:REPLY=true:[1]) false || print -- "$name"
done <file_list

모든 이름을 하나의 검색으로 결합하는 것이 더 효율적입니다. 패턴 수가 명령줄의 시스템 길이 제한에 비해 너무 크지 않은 경우 를 사용하여 모든 이름을 연결하고 -o단일 find호출을 수행하고 출력을 사후 처리할 수 있습니다. 이름에 쉘 메타 문자가 포함되어 있지 않으면(따라서 이름이 find패턴인 경우) 다음을 사용하여 후처리(테스트되지 않음)에 awk를 사용할 수 있습니다.

set -o noglob; IFS='
'
set -- $(<file_list sed -e '2,$s/^/-o\
/')
set +o noglob; unset IFS
find . \( "$@" \) -print | awk -F/ '
    BEGIN {while (getline <"file_list") {found[$0]=0}}
    wanted[$0]==0 {found[$0]=1}
    END {for (f in found) {if (found[f]==0) {print f}}}
'

또 다른 접근 방식은 Perl과 를 사용하는 것인데 File::Find, 이를 통해 디렉터리의 모든 파일에 대해 Perl 코드를 쉽게 실행할 수 있습니다.

perl -MFile::Find -l -e '
    %missing = map {chomp; $_, 1} <STDIN>;
    find(sub {delete $missing{$_}}, ".");
    print foreach sort keys %missing'

또 다른 접근 방식은 양쪽에 파일 이름 목록을 생성하고 텍스트 비교를 수행하는 것입니다. Zsh 버전:

comm -23 <(<file_list sort) <(print -rl -- **/*(:t) | sort)

답변3

첫 번째 간단한 접근 방식은 다음과 같습니다.

a) 파일 목록을 정렬합니다.

sort file.lst > sorted.lst 
for f in $(< sortd.lst) ; do find -name $f -printf "%f\n"; done > found.lst
diff sorted.lst found.lst

실종자를 찾거나

comm sorted.lst found.lst

일치하는 항목 찾기

  • 덫:
    • 파일 이름의 줄 바꿈은 처리하기 어렵습니다.
    • 파일 이름의 공백 및 유사한 내용도 좋지 않습니다. 하지만 파일 목록에 있는 파일을 제어할 수 있으므로 이 솔루션으로도 충분할 수 있지만...
  • 결점:

    • find가 파일을 찾으면 계속해서 다른 파일을 찾은 다음 다른 파일을 찾습니다. 추가 검색을 건너뛸 수 있으면 좋을 것 같습니다.
    • find는 한 번에 여러 파일을 검색할 수 있으며 몇 가지 준비가 필요합니다.

      찾기 -name a.file -또는 -name -b.file -또는 -name c.file ...

옵션을 찾을 수 있나요? 다시 말하지만, 미리 정렬된 파일 목록을 가정하면 다음과 같습니다.

 for f in $(< sorted.tmp) ; do locate --regexp "/"$f"$" > /dev/null || echo missing $f ; done

foo.bar를 검색하면 foo.ba 또는 oo.bar 파일이 --regexp-construct와 일치하지 않습니다(p가 없는 정규 표현식과 혼동하지 마세요).

검색할 특정 데이터베이스를 지정할 수 있으며 최신 결과가 필요한 경우 검색하기 전에 업데이트해야 합니다.

답변4

FIND_EXP=". -type f \( "
while read f; do
   FIND_EXP="${FIND_EXP} -iname $f -or"
done < file_list
FIND_EXP="${var%-or}"
FIND_EXP="${FIND_EXP} \)"
find ${FIND_EXP}

아마도?

관련 정보