Unix / Linuxで2つのファイルの内容が同じかどうかを確認する最も速い方法は?


231

2つのファイルに同じデータが含まれているかどうかを確認する必要があるシェルスクリプトがあります。私はこれを多くのファイルに対して実行し、スクリプトではdiffコマンドがパフォーマンスのボトルネックになっているようです。

ここに行があります:

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

if ($status) then ...

ファイルを比較するより速い方法、おそらくデフォルトの代わりにカスタムアルゴリズムがありますdiffか?


10
これはほんの一部ですが、2つのファイルが同じであるかどうかを確認するように求めているのではなく、2つのファイルが同じ内容であるかどうかを求めているのです。同じファイルには同じiノード(および同じデバイス)があります。
Zano

1
承認された回答とは異なり、この回答の測定ではdiff、との顕著な違いは認識されませんcmp
wedi

回答:


390

cmp最初のバイトの違いで止まると思います:

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

1
1つだけではないコマンドを追加するにはどうすればよいですか?ファイルをコピーして起動します。
feedc0de

9
cmp -s $old $newも動作します。-sの略--silent
ローマー2016年

7
速度を上げるために、コンテンツを比較する前にファイルサイズが等しいことを確認する必要があります。cmpがこれを行うかどうか誰かが知っていますか?
BeowulfNode42 2016年

3
複数のコマンドを実行するには、角かっこを使用できます:cmp -s old new || {エコーしない; エコーします。同じエコー; }
unfa

6
@ BeowulfNode42はい、適切な実装でcmpは、最初にファイルサイズがチェックされます。あなたはそれが含まれ、追加の最適化を確認したい場合はここではGNU版は、です:git.savannah.gnu.org/cgit/diffutils.git/tree/src/cmp.cは
ライアン・グラハム

54

@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.shfile1.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ハッシュアルゴリズムが1対1ではないからです。それらはハッシュ空間が大きく、異なる入力が異なるハッシュを生成する可能性が高いように設計されています。現実には、ハッシュ空間は有限ですが、ハッシュできるファイルの範囲はそうではありません-最終的には衝突が発生します。暗号学では、これは誕生日攻撃と呼ばれています。
意志

5
@ウィルええ、それは効果的に動作することが保証されています。機能しない確率は、数学的に言えば1/(2^511)です。誰かが意図的に衝突を作成しようとしているのではないかと心配しない限り、この方法で誤検知を生成するという考えは、実際には深刻な問題ではありません。cmpただし、ファイルが一致しない場合にファイル全体を読み取る必要がないため、さらに効率的です。
Ajedi32 2016

12
OPは最速の方法を求めました...ファイルが大きい場合は特に、ファイル全体をハッシュするよりも(cmpを使用して)一致しない最初のビットを検索する方が(一致しない場合)速くありませんか?
KoZm0kNoT 2016

3
md5は、1対多の比較を行う場合に最適です。md5ハッシュは、属性として、または各ファイルに対してデータベースに保存できます。新しいファイルが表示され、同じファイルがファイルシステムのどこかに存在するかどうかを確認する必要がある場合は、新しいファイルのハッシュを計算し、以前のすべてに対してチェックするだけです。コミット中にファイルの変更をチェックするためにGitがハッシュを使用していることは確かですが、SHA1を使用しています。
JimHough

3
@ BeowulfNode42私がコメントの前に「誰かが意図的に衝突を作成しようとしていることを心配していない限り」を付けたのはそのためです
Ajedi32

5

私は吸うと評判ポイントが足りないので、この一口をコメントとして追加することはできません。

ただし、cmpコマンドを使用する場合(および冗長にする必要がない場合)、終了ステータスを取得できます。cmpmanページごと:

FILEが「-」または欠落している場合は、標準入力を読み取ります。入力が同じ場合は終了ステータスは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"コマンドを式で直接使用できるため、より複雑な方法です。の代わりになり$?ます。その結果、コマンドの存在ステータスが比較されます。そして、それが他の答えがすることです。ところで。誰かがと格闘している場合--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ユーザー名またはグループ名に空白がある場合の問題を回避するために使用します。
トリカス

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
それも私の最初の考えでした。ただし、ハッシュは1回しか計算されないため、同じファイルを何度も比較する必要がある場合は、ハッシュは意味があります。一度だけ比較する場合は、md5とにかくファイル全体を読み取るのでcmp、最初の違いで停止すると、はるかに速くなります。
Francesco Dondi 2017

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を使用して2つのファイル間で処理を実行する場合...

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.