유닉스 / 리눅스에서 두 파일이 같은 내용을 가지고 있는지 확인하는 가장 빠른 방법은 무엇입니까?


231

두 파일에 동일한 데이터가 포함되어 있는지 여부를 확인 해야하는 쉘 스크립트가 있습니다. 많은 파일에 대해이 작업을 수행하며 스크립트에서 diff명령이 성능 병목 현상으로 보입니다.

라인은 다음과 같습니다.

diff -q $dst $new > /dev/null

if ($status) then ...

파일을 비교하는 더 빠른 방법이있을 수 diff있습니까 , 기본값 대신 사용자 정의 알고리즘 일까요?


10
이것은 실제로 nitpicking이지만 두 파일이 같은지 확인하지 않고 두 파일의 내용이 동일한 지 묻습니다. 동일한 파일에는 동일한 inode (및 동일한 장치)가 있습니다.
Zano

1
허용 대답과는 달리,에서 측정 이 답변이 사이에 주목할만한 차이를 인식하지 못합니다 diffcmp.
wedi

답변:


388

cmp첫 번째 바이트 차이에서 멈출 것이라고 믿습니다 .

cmp --silent $old $new || echo "files are different"

1
하나보다 많은 명령을 어떻게 추가 할 수 있습니까? 파일을 복사하고 부팅하고 싶습니다.
feedc0de

9
cmp -s $old $new작동합니다. -s의 약어--silent
Rohmer

7
속도 향상으로 내용을 비교하기 전에 파일 크기가 같은지 확인해야합니다. cmp가 이것을하는지 아는 사람이 있습니까?
BeowulfNode42

3
여러 명령을 실행하려면 대괄호를 사용할 수 있습니다. cmp -s old new || {반향 없음; 에코; 동일 에코; }
unfa

6
@ BeowulfNode42 예, 괜찮은 구현은 cmp파일 크기를 먼저 확인합니다. 여기에 추가 최적화를보고 싶다면 GNU 버전이 있습니다 : git.savannah.gnu.org/cgit/diffutils.git/tree/src/cmp.c
Ryan Graham

53

@Alex Howansky는 이것을 위해 'cmp --silent'를 사용했습니다. 그러나 긍정적 인 반응과 부정적인 반응이 모두 필요하므로 다음을 사용하십시오.

cmp --silent file1 file2 && echo '### SUCCESS: Files Are Identical! ###' || echo '### WARNING: Files Are Different! ###'

그런 다음 터미널에서 또는 ssh를 사용하여 상수 파일과 비교하여 파일을 확인할 수 있습니다.


16
귀하의 경우 echo success명령 (또는 당신이 그 자리에 넣어 다른 어떤 명령) 실패, 당신의 "부정적 응답"명령이 실행됩니다. "if-then-else-fi"구문을 사용해야합니다. 예를 들어, 이 간단한 예같습니다 .
와일드 카드

18

왜 두 파일 내용의 해시를 얻지 못합니까?

이 스크립트를 사용해보고 (예 : script.sh) 다음과 같이 실행하십시오. script.sh file1.txt file2.txt

#!/bin/bash

file1=`md5 $1`
file2=`md5 $2`

if [ "$file1" = "$file2" ]
then
    echo "Files have the same content"
else
    echo "Files have NOT the same content"
fi

2
해싱 알고리즘이기 때문에 @THISUSERNEEDSHELP 그것은이다 하지 하나 하나에 있습니다. 해시 공간이 넓고 다른 입력으로 인해 다른 해시를 생성 할 가능성이 높도록 설계되었습니다. 그러나 해시 공간은 유한하지만 해시 할 수있는 파일의 범위는 제한적이지 않으므로 결국 충돌이 발생합니다. 암호학에서는이를 생일 공격 이라고합니다 .
것이다

5
@ will Eh, 효과적으로 작동합니다. 작동하지 않을 확률은 수학적으로 말해서 1/(2^511)입니다. 의도적으로 충돌을 시도하는 누군가에 대해 걱정하지 않는 한이 방법이 오 탐지 를 만드는 아이디어는 실제로 심각한 문제가 아닙니다. cmp파일이 일치하지 않는 경우 전체 파일을 읽을 필요가 없기 때문에 여전히 더 효율적입니다.
Ajedi32

12
OP는 가장 빠른 방법을 요구했습니다 ... cmp를 사용하는 첫 번째 비 일치 비트를 검색하는 것이 전체 파일을 해시하는 것보다 빠릅니다 (일치하지 않는 경우). 특히 파일이 큰 경우?
KoZm0kNoT

3
일대 다 비교를 수행하는 경우 md5가 가장 좋습니다. md5 해시를 속성으로 또는 각 파일에 대한 데이터베이스에 저장할 수 있습니다. 새 파일이 나타나고 파일 시스템의 어느 곳에 동일한 파일이 있는지 확인해야하는 경우 새 파일의 해시를 계산하고 이전의 모든 파일과 비교하여 확인하면됩니다. Git이 커밋 중에 파일 변경 사항을 확인하기 위해 해싱을 사용하지만 SHA1을 사용하는지 확인하십시오.
JimHough

3
@ BeowulfNode42 "내가 의도적으로 충돌을 시도하는 누군가에 대해 걱정하지 않는 한"
Ajedi32

5

내가 평판을 얻지 못해 평판이 충분하지 않기 때문에이 음식을 의견으로 추가 할 수 없습니다.

그러나 cmp명령 을 사용 하려는 경우 (자세한 설명이 필요하지 않은 경우) 종료 상태를 파악하면됩니다. cmp매뉴얼 페이지 당 :

파일이 '-'이거나 누락 된 경우 표준 입력을 읽으십시오. 입력이 동일하면 종료 상태는 0이고, 다를 경우 1, 문제가 있으면 2입니다.

따라서 다음과 같은 작업을 수행 할 수 있습니다.

STATUS="$(cmp --silent $FILE1 $FILE2; echo $?)"  # "$?" gives exit status for each comparison

if [[$STATUS -ne 0]]; then  # if status isn't equal to 0, then execute code
    DO A COMMAND ON $FILE1
else
    DO SOMETHING ELSE
fi

예, 그러나 이것은 실제로보다 복잡한 방법입니다 . 즉, 표현식에서 직접 명령을 사용할 수 있기 때문에 cmp --silent $FILE1 $FILE2 ; if [ "$?" == "1" ]; then echo "files differ"; fi좀 더 복잡한 방법입니다 cmp --silent $FILE1 $FILE2 || echo "files differ". 대신 사용합니다 $?. 결과적으로 명령의 존재 상태가 비교됩니다. 그리고 그것은 다른 대답이하는 것입니다. btw. 누군가 어려움을 겪고 있다면 --silent(busybox) 모든 곳에서 지원되지 않습니다. 사용-s
papo

4

다르지 않은 파일의 경우, 읽기가 과거에 있었던 경우에도 모든 방법을 사용하여 두 파일을 모두 읽어야합니다.

대안이 없습니다. 따라서 특정 시점에 해시 또는 체크섬을 만들려면 전체 파일을 읽어야합니다. 큰 파일은 시간이 걸립니다.

파일 메타 데이터 검색은 큰 파일을 읽는 것보다 훨씬 빠릅니다.

파일이 다르다는 것을 확인하는 데 사용할 수있는 파일 메타 데이터가 있습니까? 파일 크기? 또는 파일의 작은 부분을 읽는 파일 명령의 결과?

파일 크기 예제 코드 조각 :

  ls -l $1 $2 | 
  awk 'NR==1{a=$5} NR==2{b=$5} 
       END{val=(a==b)?0 :1; exit( val) }'

[ $? -eq 0 ] && echo 'same' || echo 'different'  

파일 크기가 같으면 전체 파일 읽기가 고착 된 것입니다.


1
ls -n사용자 또는 그룹 이름에 공백이있는 경우 문제를 피하기 위해 사용하십시오 .
tricasse

2

cksum 명령도 사용하십시오 :

chk1=`cksum <file1> | awk -F" " '{print $1}'`
chk2=`cksum <file2> | awk -F" " '{print $1}'`

if [ $chk1 -eq $chk2 ]
then
  echo "File is identical"
else
  echo "File is not identical"
fi

cksum 명령은 파일의 바이트 수를 출력합니다. 'man cksum'을 참조하십시오.


2
저의 첫 생각이기도했습니다. 그러나 해시가 한 번만 계산되므로 동일한 파일을 여러 번 비교해야하는 경우 해시는 의미가 있습니다. 한 번만 비교하는 경우 md5어쨌든 전체 파일 을 읽으므로 cmp첫 번째 차이에서 멈추는 것이 훨씬 빠릅니다.
Francesco Dondi

0

Raspberry Pi 3B + (일부 오버레이 파일 시스템을 사용하고 있으며 주기적으로 동기화해야 함)를 사용하여 일부 테스트를 수행하면서 diff -q 및 cmp -s에 대한 자체 비교를 실행했습니다. 이것은 / dev / shm 내부의 로그이므로 디스크 액세스 속도는 문제가되지 않습니다.

[root@mypi shm]# dd if=/dev/urandom of=test.file bs=1M count=100 ; time diff -q test.file test.copy && echo diff true || echo diff false ; time cmp -s test.file test.copy && echo cmp true || echo cmp false ; cp -a test.file test.copy ; time diff -q test.file test.copy && echo diff true || echo diff false; time cmp -s test.file test.copy && echo cmp true || echo cmp false
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 6.2564 s, 16.8 MB/s
Files test.file and test.copy differ

real    0m0.008s
user    0m0.008s
sys     0m0.000s
diff false

real    0m0.009s
user    0m0.007s
sys     0m0.001s
cmp false
cp: overwrite âtest.copyâ? y

real    0m0.966s
user    0m0.447s
sys     0m0.518s
diff true

real    0m0.785s
user    0m0.211s
sys     0m0.573s
cmp true
[root@mypi shm]# pico /root/rwbscripts/utils/squish.sh

나는 그것을 두 번 실행했다. cmp -s는 내가 사용하고있는 테스트 상자에서 일관되게 약간 짧은 시간을 보냈습니다. 따라서 cmp -s를 사용하여 두 파일 사이에서 작업을 수행하려는 경우 ....

identical (){
  echo "$1" and "$2" are the same.
  echo This is a function, you can put whatever you want in here.
}
different () {
  echo "$1" and "$2" are different.
  echo This is a function, you can put whatever you want in here, too.
}
cmp -s "$FILEA" "$FILEB" && identical "$FILEA" "$FILEB" || different "$FILEA" "$FILEB"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.