60個の大容量ファイルを比較し、すべてのファイルに共通のラインのみ出力

60個の大容量ファイルを比較し、すべてのファイルに共通のラインのみ出力

私はそれぞれ約10,000行を含む60個のファイルを持っています。各行には文字列が含まれています。

すべてのファイルに共通の文字列を見つけたいです。

正確に一致するものが必要なので、行全体を比較します。

答え1

この試み、

awk '
    BEGINFILE{fnum++; delete f;}
    !f[$0]++{s[$0]++;}
    END {for (l in s){if (s[l] == fnum) print l}}
' files*

説明する:

  • BEGINFILE { ... }各ファイルの先頭から実行

  • !f[$0]++ { ... }ファイルの最初の行でのみ実行(f[$0]0(false)の場合)

    • s[$0]++行カウンタをインクリメントします。
  • END { ... }前回実行

    • for (l in s){if (s[l] == fnum) print l}行を繰り返し、ファイル数と同じ回数で発生する各行を印刷します。

600,000行はメモリに十分です。それ以外の場合は、sブロックより小さいものfnumをすべて削除する危険がありますBEGINFILE{...}

答え2

Bashのパラレルバージョン。メモリより大きいファイルで動作します。

export LC_ALL=C
comm -12 \
  <(comm -12 \
    <(comm -12 \
      <(comm -12 \
        <(comm -12  <(comm -12  <(sort 1) <(sort 2);) <(comm -12  <(sort 3) <(sort 4););) \
        <(comm -12  <(comm -12  <(sort 5) <(sort 6);) <(comm -12  <(sort 7) <(sort 8);););) \
      <(comm -12 \
        <(comm -12  <(comm -12  <(sort 9) <(sort 10);) <(comm -12  <(sort 11) <(sort 12););) \
        <(comm -12  <(comm -12  <(sort 13) <(sort 14);) <(comm -12  <(sort 15) <(sort 16););););) \
    <(comm -12 \
      <(comm -12 \
        <(comm -12  <(comm -12  <(sort 17) <(sort 18);) <(comm -12  <(sort 19) <(sort 20););) \
        <(comm -12  <(comm -12  <(sort 21) <(sort 22);) <(comm -12  <(sort 23) <(sort 24);););) \
      <(comm -12 \
        <(comm -12  <(comm -12  <(sort 25) <(sort 26);) <(comm -12  <(sort 27) <(sort 28););) \
        <(comm -12  <(comm -12  <(sort 29) <(sort 30);) <(comm -12  <(sort 31) <(sort 32);););););) \
  <(comm -12 \
    <(comm -12 \
      <(comm -12 \
        <(comm -12  <(comm -12  <(sort 33) <(sort 34);) <(comm -12  <(sort 35) <(sort 36););) \
        <(comm -12  <(comm -12  <(sort 37) <(sort 38);) <(comm -12  <(sort 39) <(sort 40);););) \
      <(comm -12 \
        <(comm -12  <(comm -12  <(sort 41) <(sort 42);) <(comm -12  <(sort 43) <(sort 44););) \
        <(comm -12  <(comm -12  <(sort 45) <(sort 46);) <(comm -12  <(sort 47) <(sort 48););););) \
    <(comm -12 \
      <(comm -12 \
        <(comm -12  <(comm -12  <(sort 49) <(sort 50);) <(comm -12  <(sort 51) <(sort 52););) \
        <(comm -12  <(comm -12  <(sort 53) <(sort 54);) <(comm -12  <(sort 55) <(sort 56);););) \
      <(cat  <(comm -12  <(comm -12  <(sort 57) <(sort 58);) <(comm -12  <(sort 59) <(sort 60););) ;);););

ファイルがソートされている場合sortcat

答え3

For、ラベル付き配列でzsh配列交差演算子を使用します。${a:*b}ユニークフラグ(また、$(<file)ksh演算子とfパラメータ拡張フラグを使用して改行を分割する):

#! /bin/zsh -
typeset -U all list
all=(${(f)"$(<${1?})"}); shift
for file do
  list=(${(f)"$(<$file)"})
  all=(${all:*list})
done
print -rC1 -- $all

(スクリプトはファイルリストを引数として使用し、空白行は無視されます。)

答え4

そしてjoin

cp a jnd
for f in a b c; do join jnd $f >j__; cp j__ jnd; done

3つのファイルa、b、cには数字(1-6、3-8、5-9)しかありません。これは、3つすべてに共通する2行(数字、文字列)です。

]# cat jnd
5
6

cp特にその間にはエレガントでも効率的でもありません。ただし、簡単に並列に動作できます。ファイルサブグループ(for f in a*)を選択してファイルに一意の名前を付けると、複数のサブグループを一度に実行できます。それでも結果をリンクする必要があります... - 64個のファイルに対してそれぞれ8個のファイルを連結する8個のスレッドがあり、残りの8個のファイルを再び4個のスレッドに分割できます。

関連情報