ファイル内の列で重複を検索する

ファイル内の列で重複を検索する

ファイル パスとそれらの md5sum がセミコロンで区切られ、md5 ハッシュでソートされた入力ファイルがあります。

/media/LaCie/Images/recup2/recup_dir.1/f1295328.jpg;0080ececd3da8533f5d11e449cf73287
/media/LaCie/Documents/pics/897_FUJI/DSCF7042.JPG;0081cd15705f0c541995e13ad3e405b8
/media/LaCie/Documents/Pictures/124_FUJI/DSCF4729.JPG;00829232ae6b181654ee87ff32d161f8
/media/LaCie/Images/Trashes/501/IMG_0651.JPG;00833c74523d5361641af863f5d92387
/media/LaCie/Images/2009-09/IMG_0651.JPG;00833c74523d5361641af863f5d92387

ハッシュに基づいて重複を見つけて印刷する方法を知りたいのですが、上記の入力の出力は次のようになります。

/media/LaCie/Images/Trashes/501/IMG_0651.JPG;00833c74523d5361641af863f5d92387
/media/LaCie/Images/2009-09/IMG_0651.JPG;00833c74523d5361641af863f5d92387

試してみましたuniqが、フィールド区切り文字をスペースからセミコロンに変更する方法が見つかりませんでした(一部のファイルパスにはスペースが含まれている場合があります)

答え1

パスにスペースやセミコロンが含まれていない場合は、セミコロンをスペースに変更します。

tr ';' ' ' | uniq -f 1 -d | tr ' ' ';'

パスにスペースは含まれているがタブやセミコロンが含まれていない場合は、基本的に同じことを行うことができますが、一時的にスペースをセミコロンに変換し、フィールド区切り文字としてタブを使用します。

tr '; ' '\t;' | uniq -f 1 -d | tr '\t;' '; '

ファイル名に関して何も仮定したくない場合は (改行を含まないこと以外)、代わりに awk にその作業を実行させることができます。

awk -F ';' '{
    if ($NF == current) {
        if (first != "") print first;
        first = "";
        print;
    } else {
        first = $0;
        current = $NF;
    }
}'

答え2

考えられる解決策としては、以下が挙げられますawk

awk -F";" 'FNR == NR { x[$2]++; next; } { if ($2 in x && x[$2] > 1) print; }' file file

この場合の注意点は、ファイルが 2 回読み取られることです。最初のパスでは、繰り返しをカウントして配列に格納し、2 番目のパスでは、カウンターが 1 より大きい場合に行を出力します。

答え3

かなり簡単です(ボーナスポイントとして、ビットもperl実行できます)。md5sum

しかし、次のようになります:

#!/usr/bin/env perl
use strict;
use warnings;

my %file_md5; 

while ( <> ){
   chomp; 
   my ( $filename, $hash ) = split /;/; 
   if ( $file_md5{$hash} ) { 
       print "$filename has the same md5sum as $file_md5{$hash}\n";
   }
   $file_md5{$hash} = $filename;
}

メモは魔法のファイルハンドルです。コマンドライン<>から、またはファイルからスクリプトにパイプされたデータを取得します。STDIN./myscript.pl file_containing_data

答え4

よりスマートなソリューションとしては、cutmd5sum を取り出し、それを実行してuniq -cカウントを取得し、を使用して実際に一意の値を切り取り、残りの md5sum をループawkに渡して元のファイルからの一致する値に渡す、ブルート フォースの「ワンライナー」があります。これは、Gilles の all-awk ソリューションほどエレガントではなく、入力ファイルを 2 回読み取るという欠点もあります。forgrep

for md5 in $(cut -d\; -f2 inputfile-here | uniq -c | awk '$1 > 1 { print $2 }')
do 
  grep ";$md5\$" inputfile-here
  echo  ## gratuitous blank line to separate the duplicates
done

サンプル入力ファイルに重複を追加しました:

/media/LaCie/Images/recup2/recup_dir.1/f1295328.jpg;0080ececd3da8533f5d11e449cf73287
/media/LaCie/Documents/pics/897_FUJI/DSCF7042.JPG;0081cd15705f0c541995e13ad3e405b8
/media/LaCie/Documents/Pictures/124_FUJI/DSCF4729.JPG;00829232ae6b181654ee87ff32d161f8
/media/LaCie/Documents/Pictures/124_FUJI/DSCF4729-1.JPG;00829232ae6b181654ee87ff32d161f8
/media/LaCie/Documents/Pictures/124_FUJI/DSCF4729-2.JPG;00829232ae6b181654ee87ff32d161f8
/media/LaCie/Images/Trashes/501/IMG_0651.JPG;00833c74523d5361641af863f5d92387
/media/LaCie/Images/2009-09/IMG_0651.JPG;00833c74523d5361641af863f5d92387

上記のループにより次の結果が生成されます。

/media/LaCie/Documents/Pictures/124_FUJI/DSCF4729.JPG;00829232ae6b181654ee87ff32d161f8
/media/LaCie/Documents/Pictures/124_FUJI/DSCF4729-1.JPG;00829232ae6b181654ee87ff32d161f8
/media/LaCie/Documents/Pictures/124_FUJI/DSCF4729-2.JPG;00829232ae6b181654ee87ff32d161f8

/media/LaCie/Images/Trashes/501/IMG_0651.JPG;00833c74523d5361641af863f5d92387
/media/LaCie/Images/2009-09/IMG_0651.JPG;00833c74523d5361641af863f5d92387

関連情報