동일한 파일을 포함하고 동일한 디렉토리 구조를 갖는 두 개의 디렉토리가 있습니다.
이 디렉토리 중 하나에 무언가가 빠져 있다고 생각합니다.
bash 쉘을 사용하여 내 디렉토리를 비교하고 그중 하나에 다른 파일이 없는지 확인하는 방법이 있습니까?
동일한 파일을 포함하고 동일한 디렉토리 구조를 갖는 두 개의 디렉토리가 있습니다.
이 디렉토리 중 하나에 무언가가 빠져 있다고 생각합니다.
bash 쉘을 사용하여 내 디렉토리를 비교하고 그중 하나에 다른 파일이 없는지 확인하는 방법이 있습니까?
답변:
이 비교를 할 수있는 좋은 방법은 사용하는 것입니다 find
와 md5sum
다음, diff
.
find를 사용하여 디렉토리의 모든 파일을 나열한 다음 각 파일의 md5 해시를 계산하고 파일 이름별로 파일을 파이프하여 파일로 파이프하십시오.
find /dir1/ -type f -exec md5sum {} + | sort -k 2 > dir1.txt
다른 디렉토리와 동일한 절차를 수행하십시오.
find /dir2/ -type f -exec md5sum {} + | sort -k 2 > dir2.txt
그런 다음 결과 두 파일을 다음과 비교하십시오 diff
.
diff -u dir1.txt dir2.txt
또는 프로세스 대체를 사용하는 단일 명령으로 :
diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2) <(find /dir2/ -type f -exec md5sum {} + | sort -k 2)
변경 사항 만 보려면 다음을 수행하십시오.
diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2 | cut -f1 -d" ") <(find /dir2/ -type f -exec md5sum {} + | sort -k 2 | cut -f1 -d" ")
cut 명령은 diff와 비교할 해시 (첫 번째 필드) 만 인쇄합니다. 그렇지 않으면 해시가 동일하더라도 디렉토리 경로가 다르기 때문에 diff는 모든 행을 인쇄합니다.
그러나 어떤 파일이 변경되었는지 알 수 없습니다 ...
이를 위해 다음과 같은 것을 시도 할 수 있습니다
diff <(find /dir1/ -type f -exec md5sum {} + | sort -k 2 | sed 's/ .*\// /') <(find /dir2/ -type f -exec md5sum {} + | sort -k 2 | sed 's/ .*\// /')
이 전략은 비교할 두 디렉토리가 동일한 시스템에 있지 않고 두 디렉토리에서 파일이 동일한 지 확인해야 할 때 매우 유용합니다.
작업을 수행하는 또 다른 좋은 방법은 Git의 diff
명령을 사용하는 것입니다 (파일에 다른 권한이있는 경우 문제가 발생할 수 있음-> 모든 파일이 출력에 나열 됨).
git diff --no-index dir1/ dir2/
find
파일을 나열하는 순서 는 두 디렉토리간에 일반적으로 다르기 때문에 추가 정렬 단계 없이는 작동하지 않습니다 .
diff
파일에 사용하는 것처럼 명령을 사용할 수 있습니다 .
diff <directory1> <directory2>
하위 폴더와 -file도 보려면 다음 -r
옵션을 사용할 수 있습니다 .
diff -r <directory1> <directory2>
diff
디렉토리에서도 작동 하지는 않았지만 (man diff는이를 확인했지만) 서브 디렉토리 내부의 서브 디렉토리 변경 사항을 재귀 적으로 확인하지는 않습니다.
a/b/c/d/a
, x/b/c/d/b
. 무엇을 diff a x
제공 하는지 확인하십시오 .
-r
옵션 을 사용해야합니다 . 즉 ( diff -r a x
) 나에게 준다 :Only in a/b/c/d: a. only in x/b/c/d: b.
내용이 아닌 파일 이름 만 비교하는 대안은 다음과 같습니다.
diff <(cd folder1 && find . | sort) <(cd folder2 && find . | sort)
이것은 누락 된 파일을 나열하는 쉬운 방법이지만 물론 이름은 같지만 내용이 다른 파일을 감지하지 못합니다 !
(개인적으로 나는 내 자신의 diffdirs
스크립트를 사용하지만 더 큰 라이브러리의 일부입니다 .)
diff
가 현재 지원하지 않는 0 구분 기호를 사용할 수 있습니다 . 그러나 git.savannah.gnu.org/cgit/coreutils.git/commit/comm
이후로 지원하는 것이 있습니다. 따라서 가까운 코어 유틸리티에 도달 하면 다음을 수행 할 수 있습니다 comm -z <(cd folder1 && find -print0 | sort) <(cd folder2 && find -print0 | sort -z)
(이 출력은 형식으로 더 변환해야 할 수도 있습니다) --output-delimiter
매개 변수 및 추가 도구 를 사용해야합니다 .
아마도 하나의 옵션은 rsync를 두 번 실행하는 것입니다.
rsync -r -n -t -v -O --progress -c -s /dir1/ /dir2/
이전 줄을 사용하면 dir1에 있고 dir2에 다르거 나 누락 된 파일을 얻을 수 있습니다.
rsync -r -n -t -v -O --progress -c -s /dir2/ /dir1/
dir2와 동일
#from the rsync --help :
-r, --recursive recurse into directories
-n, --dry-run perform a trial run with no changes made
-t, --times preserve modification times
-v, --verbose increase verbosity
--progress show progress during transfer
-c, --checksum skip based on checksum, not mod-time & size
-s, --protect-args no space-splitting; only wildcard special-chars
-O, --omit-dir-times omit directories from --times
-n
옵션을 삭제 하여 변경을 수행 할 수 있습니다 . 파일 목록을 두 번째 폴더로 복사하고 있습니다.
그렇게하는 경우 -u
새 파일을 덮어 쓰지 않기 위해을 사용하는 것이 좋습니다 .
-u, --update skip files that are newer on the receiver
원 라이너 :
rsync -rtvcsOu -n --progress /dir1/ /dir2/ && rsync -rtvcsOu -n --progress /dir2/ /dir1/
각 파일을 확장 가능하고 축소 가능하게하려면 출력 diff -r
을 Vim으로 파이프 할 수 있습니다 .
먼저 Vim에게 접는 규칙을 지어 보자.
mkdir -p ~/.vim/ftplugin
echo "set foldexpr=getline(v:lnum)=~'^diff.*'?'>1':1 foldmethod=expr fdc=2" >> ~/.vim/ftplugin/diff.vim
이제는
diff -r dir1 dir2 | vim -
당신은 칠 수 zo
및 zc
개폐 주름 할 수 있습니다. Vim에서 나가려면:q<Enter>
파이썬에서 매우 쉬운 작업 :
python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' DIR1 DIR2
DIR1
및의 실제 값을 대체하십시오 DIR2
.
다음은 샘플 실행입니다.
$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Desktop
SAME
$ python -c 'import os,sys;d1=os.listdir(sys.argv[1]);d2=os.listdir(sys.argv[2]);d1.sort();d2.sort();x="SAME" if d1 == d2 else "DIFF";print x' Desktop/ Pictures/
DIFF
가독성을 위해 다음은 하나의 라이너 대신 실제 스크립트입니다.
#!/usr/bin/env python
import os, sys
d1 = os.listdir(sys.argv[1])
d2 = os.listdir(sys.argv[2])
d1.sort()
d2.sort()
if d1 == d2:
print("SAME")
else:
print("DIFF")
os.listdir
특정 순서를 제공하지 않습니다. 따라서 목록은 다른 순서로 동일한 것을 가질 수 있으며 비교는 실패합니다.
Sergiy의 답변에서 영감을 받아 두 디렉토리를 비교하기 위해 자체 Python 스크립트를 작성했습니다.
다른 많은 솔루션과 달리 파일의 내용을 비교하지 않습니다. 또한 디렉토리 중 하나에서 누락 된 하위 디렉토리에 들어 가지 않습니다. 따라서 출력은 매우 간결하며 스크립트는 큰 디렉토리에서 빠르게 작동합니다.
#!/usr/bin/env python3
import os, sys
def compare_dirs(d1: "old directory name", d2: "new directory name"):
def print_local(a, msg):
print('DIR ' if a[2] else 'FILE', a[1], msg)
# ensure validity
for d in [d1,d2]:
if not os.path.isdir(d):
raise ValueError("not a directory: " + d)
# get relative path
l1 = [(x,os.path.join(d1,x)) for x in os.listdir(d1)]
l2 = [(x,os.path.join(d2,x)) for x in os.listdir(d2)]
# determine type: directory or file?
l1 = sorted([(x,y,os.path.isdir(y)) for x,y in l1])
l2 = sorted([(x,y,os.path.isdir(y)) for x,y in l2])
i1 = i2 = 0
common_dirs = []
while i1<len(l1) and i2<len(l2):
if l1[i1][0] == l2[i2][0]: # same name
if l1[i1][2] == l2[i2][2]: # same type
if l1[i1][2]: # remember this folder for recursion
common_dirs.append((l1[i1][1], l2[i2][1]))
else:
print_local(l1[i1],'type changed')
i1 += 1
i2 += 1
elif l1[i1][0]<l2[i2][0]:
print_local(l1[i1],'removed')
i1 += 1
elif l1[i1][0]>l2[i2][0]:
print_local(l2[i2],'added')
i2 += 1
while i1<len(l1):
print_local(l1[i1],'removed')
i1 += 1
while i2<len(l2):
print_local(l2[i2],'added')
i2 += 1
# compare subfolders recursively
for sd1,sd2 in common_dirs:
compare_dirs(sd1, sd2)
if __name__=="__main__":
compare_dirs(sys.argv[1], sys.argv[2])
파일을라는 파일에 저장하면 compare_dirs.py
Python3.x로 실행할 수 있습니다.
python3 compare_dirs.py dir1 dir2
샘플 출력 :
user@laptop:~$ python3 compare_dirs.py old/ new/
DIR old/out/flavor-domino removed
DIR new/out/flavor-maxim2 added
DIR old/target/vendor/flavor-domino removed
DIR new/target/vendor/flavor-maxim2 added
FILE old/tmp/.kconfig-flavor_domino removed
FILE new/tmp/.kconfig-flavor_maxim2 added
DIR new/tools/tools/LiveSuit_For_Linux64 added
추신 : 잠재적 변경 사항에 대해 파일 크기와 파일 해시를 비교 해야하는 경우 https://gist.github.com/amakukha/f489cbde2afd32817f8e866cf4abe779에 업데이트 된 스크립트를 게시했습니다.
cmpdirs dir1 dir2 '/\.git/'
bash --version
무엇입니까?