ディレクトリのファイル比較

ディレクトリのファイル比較

ディレクトリにx個のファイルがあり(x = 100より大きい)、このファイルの違いを比較したいとします。これをどのように実行できますか?私はUbuntu 18.04マシンを実行しています。議論のために、ディレクトリが/home/user1/music_list/で、そのディレクトリにあるファイルの1つが/home/user1/music_list/jazz1.txtであるとします。

答え1

これは実際にはファイルが本質的に同じかどうかによって異なります。何千もの比較を提示することも、「参照バージョン」や一連の漸進的な修正を識別できない場合は完全に混乱します。

一度は、信頼性の問題がある排出メカニズムの問題を解決するように求められたことがあります。電力網サイトの各階層には、16,000個のイメージファイル、つまり250万個のファイルを持つ160個のサーバーがあります。

基本的に最も人気のあるバージョンに投票してもらいました。各サーバーには独自のファイルチェックサムがあり、チェックサム、日付、サイズ、名前のリストを私に送信します。チェックサムにグループ化して計算します。コレクション全体で100%一貫性のあるすべてのファイルが利用可能です。ケースの80%以上に一致するものには、更新がないサーバーが表示されます。 20%未満の場合、削除に失敗したか悪意のあるテストファイルです。 20~80%の範囲に入る人はほとんどいません。

私のユースケースでは、間違った名前またはパスで別のサーバーにアップロードされたイメージファイルを検出するのも簡単でした。

このアプローチは問題を解決できないかもしれませんが、必要な詳細比較の数を大幅に減らします。

答え2

このスクリプトを試してみてください。

diff希望の出力に応じて、またはコマンドを追加しました。comm

for i in /home/user1/music_list/*.txt; do
        index_file="$i"
        echo "$(tput setaf 1)Comparing "$i" $(tput sgr 0)"
        for n in /home/user1/music_list/*.txt; do
                next_file="$n"
                echo "$(tput setaf 5)With "$n" $(tput sgr 0)"
                #comm -3 <(sort "$index_file") <(sort "$next_file")
                diff -s <(sort "$index_file") <(sort "$next_file")
                shift
        done
done

に出力comm

Comparing z.txt
With z1.txt
With z2.txt
1
        2
With z3.txt
1
        22
With z4.txt
1
        222

comm名前が同じ場合、名前は印刷されますが出力されません。z1.txt

に出力diff

Comparing z.txt
With z1.txt
Files /dev/fd/63 and /dev/fd/62 are identical
With z2.txt
1c1
< 1
---
> 2
With z3.txt
1c1
< 1
---
> 22
With z4.txt
1c1
< 1
---
> 222

答え3

/some/dirすべての一般ファイルを1対1で(再帰的に)比較するには、次のようにしますzsh

function {
  local fileA fileB
  for fileA do
    shift
    for fileB do
      diff -su $fileA $fileB
    done
  done
} /some/dir/**/*(ND.)

これは、同じ形式とコンテキストの違い-uとファイルが同じ場合の-s(非標準)レポートを示しています。

ただし、ファイルが100を超える場合は、数千回の1対1の比較が必要です。

GNUを使用すると、オプションをdiff追加して匿名関数の出力を渡すことで、その出力をより受け入れ可能にすることができます。--color=alwaysdiffless -R

bash代わりにと同じですzshが、バージョン4.4以降(用)とユーティリティreadarray -d(および拡張用)のGNU実装(または互換性)を想定しています。findsort-print0-z

(
  readarray -td '' files < <(
    find /some/dir/ -type f -print0 | sort -z)
  set -- "${files[@]}"
  for fileA do
    shift
    for fileB do
      diff -su "$fileA" "$fileB"
    done
  done
)

重複する項目が多い場合は、まずどのファイルが同じかを確認してから、同じファイル内の各グループから1つのファイルのみを選択して、他のグループの1つのファイルと比較することで、比較回数を減らすことができます。

そしてzsh

typeset -A set
files=(/some/dir/**/*(ND.))
for file in $files; do
  sum=$(sha1sum < $file) || continue
  # store the list of files having a given checksum NUL delimited
  # in an associative array
  set[$sum]+=$file$'\0'
done
sums=(${(k)set})
for sum1 in $sums; do
  shift 1 sums
  files1=(${(0)set[$sum1]}) # split on NUL
  (( $#files < 2 )) || print -r All of ${(j[, ])files1} are identical
  for sum2 in $sums; do
    files2=(${(0)set[$sum2]})
    diff -u $files1[1] $files2[1]
  done
done

(検証されていません)。

答え4

/home/user1/music_list/ディレクトリにあるファイルが1つだけ固有であることを私に伝えることで、上記の問題が改善されたとします。唯一のファイルが何であるかを見つけるには、次の答えを検討し、どう思うか教えてください。

$diff -r --from-file=/home/user1/music_list/jazz1.txt /home/user1/music_list/

アイデアは、./jazz.txtディレクトリ内のファイルを同じディレクトリ内の他のすべてのファイルと比較して、どのファイルがjazz.txtと異なるかを確認できることです。

関連情報