bashでディレクトリ内のすべてのファイルを比較するには?

bashでディレクトリ内のすべてのファイルを比較するには?

与えられた例:

dir1/
 file1
 file2
 file3
 file4
  • file1-file2, file1-file3, file1-file4ではどうやって比較しますかfile2->file3, file2->file4?この例では、名前はfile_numberですが、次のようにすることもできます。どんな名前
  • デフォルトでは、あるdiffファイルを他のファイルと比較するのではなく、すべてのファイルをすべてのファイルと比較します。

私は努力してきました:

for f in $(find ./ -type f | sort | uniq); do

    compare=$(diff -rq "$f" "$1" &>/dev/null)
    if [[ $compare -eq $? ]]; then
        echo "$(basename "$f") yes equal $1"
    else
        echo "$(basename "$f") no equal $1"
    fi
done

返品

./file1 yes equal ./file1
./file2 no equal ./file1
./file3 yes equal ./file1
./script no equal ./file1
./sd no equal ./file1
  • 任意のファイル番号のみfile1と比較
  • 別のループが必要なようですが、今では[バブルソートアルゴリズムのような]インベントリがあります。
  • file1 と同じ file1 [同じファイル] 比較を停止する別の IF 文を作成する方法

ベストアンサー1

はい、2つのループが必要です。しかし、diff出力を使用できるdiff/ dev / nullで削除するので、そうする必要はないようです。cmp

たとえば、

#!/bin/bash

# Read the list of files into an array called $files - we're iterating over
# the same list of files twice, but there's no need to run find twice.
#
# This uses NUL as the separator between filenames, so will work with
# filenames containing ANY valid character. Requires GNU find and GNU
# sort or non-GNU versions that support the `-print0` and `-z` options.
#
# The `-maxdepth 1` predicate prevents recursion into subdirs, remove it
# if that's not what you want.
mapfile -d '' -t files < <(find ./ -maxdepth 1 -type f -print0 | sort -z -u)

for a in "${files[@]}" ; do
  for b in "${files[@]}" ; do
    if [ ! "$a" = "$b" ] ; then
      if cmp --quiet "$a" "$b" ; then
        echo "Yes. $a is equal to $b"
      else
        echo "No. $a is not equal to $b"
      fi
    fi
  done
done

しかし、これを行うと、多くの出力が生成されます(n×(n-1)出力ライン、ここでnはファイルの数)。個人的に他のファイルと同じファイルは、固有のファイルよりもはるかに一般的ではない可能性が高いため、else行を削除またはコメントアウトします。echo "No...."


また、ファイルabcとファイルxyzが同じ場合は、ファイルを2回比較し、Yesを2回印刷します。

Yes. ./abc is equal to ./xyz
Yes. ./xyz is equal to ./abc

これを防ぐ方法はいくつかあります。最も簡単な方法は、連想配列を使用して互いに比較するファイルを追跡することです。例えば

#!/bin/bash

# Read the list of files into an array called $files
mapfile -d '' -t files < <(find ./ -maxdepth 1 -type f -print0 | sort -z -u)

# declare that $seen is an associative array
declare -A seen

for a in "${files[@]}" ; do
  for b in "${files[@]}" ; do
    if [ ! "$a" = "$b" ] && [ -z "${seen[$a$b]}" ] && [ -z "${seen[$b$a]}" ] ; then
      seen[$a$b]=1
      seen[$b$a]=1
      if cmp --quiet "$a" "$b" ; then
        echo "Yes. $a is equal to $b"
      #else
      #  echo "No. $a is not equal to $b"
      fi
    fi
  done
done

おすすめ記事