왜

정확히 동일한 파일을 포함해야 하는 두 개의 폴더가 있는데 파일 수를 보면 서로 다릅니다. 어떤 파일/폴더가 하나에는 있지만 다른 파일/폴더에는 없는지 알고 싶습니다. 아이디어는 모든 파일을 나열한 다음 comm을 사용하여 두 폴더 간의 차이점을 찾는 것입니다.

질문

/path/to/dir 및 /path/to/dir/file 형식으로 파일 및 폴더 목록을 반복적으로 만드는 방법은 무엇입니까?

중요 사항

운영 체제: Windows 11, 하위 시스템 Ubuntu 20.04.4 LTS

위치 폴더: 네트워크 드라이브 1개, 로컬 드라이브 1개

폴더 크기: 각각 ~2TB

답변1

알아채다목차Unix의 파일은 다양한 유형의 파일 중 하나일 뿐입니다. find를 사용하여 검색 하거나 zsh glob 의 한정자를 -type d사용할 수 있습니다. /다른 유형문서포함하다일반 파일( -type f, .글로벌 한정자, 아마도 당신은문서)뿐만 아니라 심볼릭 링크( -type l/ @), 장치, fifo, 소켓...

파일 유형 가져오기목차, 넌 할 수있어:

find dir1/ -type d

다른 유형의 파일의 경우:

find dir1/ ! -type d

에 대해서도 마찬가지입니다 dir2.

세 가지 주요 문제가 있습니다.

  • 인쇄된 경로는 dir1/for dir1dir2/for 로 시작하므로 dir2비교가 더 어려워집니다.
  • 순서는 무작위입니다.
  • 파일 경로는 한 줄에 하나씩 작성되지만 줄 바꿈은 파일 경로의 줄 바꿈만큼 유효합니다. 즉, 파일 경로가 여러 줄로 구성될 수 있으므로 출력을 안정적으로 후처리할 수 없습니다.

find이러한 문제는 GNU를 통해 sort다음 방법을 사용하여 해결할 수 있습니다 .

find dir1/ -type f -printf '%P\0' | LC_ALL=C sort -z

어디:

  • %P인쇄 파일 경로dir1을 기준으로
  • 목록을 정렬합니다(C 로케일에서는 파일 경로가 텍스트로 구성될 필요가 없으므로).
  • 0은 파일 경로에 나타날 수 없는 유일한 바이트이기 때문에 줄 대신 NUL로 구분된 레코드를 사용합니다.

이제 해당 목록을 다음과 비교할 수 있습니다.

list() {
  find "$@" -printf '%P\0' | LC_ALL=C sort -z
}
echo Directory differences:
comm -z3 <(list dir1/ -type d) <(list dir2/ -type d) | tr '\0' '\n'
echo Non-directory differences:
comm -z3 <(list dir1/ ! -type d) <(list dir2/ ! -type d) | tr '\0' '\n'

comm표시를 위해 NUL을 개행 문자로 다시 변환하고 TAB을 사용하여 파일 경로에서 다시 유효한 열을 분리하기 때문에 이 출력을 안정적으로 사후 처리할 수 없습니다 .

또는 zsh 배열로 목록을 가져오고 해당 배열 비교 연산자를 사용할 수 있습니다.

dirs_in_dir1=( dir1/**/*(ND/:s:dir1/::) )
dirs_in_dir2=( dir2/**/*(ND/:s:dir2/::) )
nondirs_in_dir1=( dir1/**/*(ND^/:s:dir1/::) )
nondirs_in_dir2=( dir2/**/*(ND^/:s:dir2/::) )

그 다음에:

dirs_only_in_dir1=( ${dirs_in_dir1:|dirs_in_dir2} )
dirs_only_in_dir2=( ${dirs_in_dir2:|dirs_in_dir1} )
nondirs_only_in_dir1=( ${nondirs_in_dir1:|nondirs_in_dir2} )
nondirs_only_in_dir2=( ${nondirs_in_dir2:|nondirs_in_dir1} )

그리고 이 배열 을 olumn print에 넣는 등의 작업을 수행합니다 .r1 C

print -rC1 -- $array

(또는 N옵션을 추가하여 후처리가 가능하도록 UL을 분리하였습니다 -N.)

답변2

이 중 어떤 것도 필요하지 않습니다 diff -qr dir1 dir2. 예를 들면 다음과 같습니다.

$ tree
.
├── dir1
│   ├── file1
│   ├── file3
│   ├── file4
│   ├── file6
│   ├── file7
│   ├── file8
│   └── subdir1
│       ├── dsaf
│       ├── sufile1
│       └── sufile3
└── dir2
    ├── file1
    ├── file2
    ├── file3
    ├── file4
    ├── file9
    └── subdir1
        ├── sufile1
        └── sufile3

4 directories, 16 files

이제 두 디렉터리에서 실행하면 diff -qr( -r"재귀"의 경우 -q파일이 다를 때만 보고하고 실제 차이점은 보고하지 않음) 다음과 같은 결과를 얻습니다.

$ diff -qr dir1/ dir2/
Only in dir2/: file2
Only in dir1/: file6
Only in dir1/: file7
Only in dir1/: file8
Only in dir2/: file9
Only in dir1/subdir1: dsaf

즉, 파일 목록을 얻는 방법은 다음과 같습니다 find.

$ find dir1 -type f
dir1/subdir1/dsaf
dir1/subdir1/sufile1
dir1/subdir1/sufile3
dir1/file6
dir1/file1
dir1/file8
dir1/file4
dir1/file7
dir1/file3

그런 다음 다음을 사용하여 두 디렉터리의 출력을 제거 dir1/하고 dir2/사용 하고 비교할 수 있습니다.sed프로세스 교체이를 지원하는 쉘에서:

$ comm -3 <(find dir1 -type f | sed 's|dir1/||' | sort) <(find dir2 -type f | sed 's|dir2/||' | sort)
    file2
file6
file7
file8
    file9
subdir1/dsaf

이는 파일 이름에 개행 문자가 없다고 가정합니다. 이러한 문제를 처리해야 하는 경우 diff -r위의 방법을 사용하면 됩니다.

답변3

노력하다

 cd /path/1
 find . -type d -print | sort > list1.dir
 find . -type f -print | sort > list1.file
 cd /path/2
 find . -type d -print | sort > list2.dir
 find . -type f -print | sort > list2.file
  • sort동일한 순서와 더 작은 diff결과를 보장하는 데 사용됩니다.comm
  • 결과를 "오염" 시키지 list1.file않도록 절대 대상 파일 이름을 사용할 수 있습니다 .list2.file

관련 정보