web-dev-qa-db-ja.com

Unix / Linuxで2つのファイルが同じであるかどうかを判断するための最速の方法

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

ここに行があります:

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

if ($status) then ...

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

181
JDS

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

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

@Alex Howanskyがこれに 'cmp --silent'を使用しているのが好きです。しかし、私はポジティブとネガティブの両方の対応が必要です。

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

その後、ターミナルまたはsshを使用してこれを実行し、ファイルを定数ファイルと照合します。

42
pn1 dude

両方のファイルのコンテンツのハッシュを取得しないのはなぜですか。

このスクリプトを試して、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
16
jabaldonedo

違いがないファイルの場合、読み取りが過去のものであっても、どの方法でも両方のファイルを完全に読み取る必要があります。

代替案はありません。そのため、ある時点でハッシュまたはチェックサムを作成するには、ファイル全体を読み取る必要があります。大きなファイルは時間がかかります。

ファイルメタデータの取得は、大きなファイルを読み込むよりもはるかに高速です。

ファイルが異なることを確認するために使用できるファイルメタデータはありますか。ファイルサイズ ?それとも、ファイルのごく一部を読み取っただけのfileコマンドの結果なのでしょうか。

ファイルサイズの例のコードの一部:

  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'  

ファイルが同じサイズであれば、あなたは完全なファイル読み取りで立ち往生しています。

4
jim mcnamara

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
Nono Taps

私はしゃべるし、十分な評判ポイントを持っていないので、私はこの一口をコメントとして加えることができません。

しかし、cmpコマンドを使用する(そして冗長にする必要はない/したくない)場合は、終了ステータスを取得するだけです。 cmpのmanページで:

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
1
Gregory Martin

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は一貫して私が使っていたテストボックス上でわずかに短い時間を持っていました。 2つのファイル間で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"
0
Jack Simth