複数のファイル間の共通点を見つける

複数のファイル間の共通点を見つける

次のようなファイルが4つあります。

       file A
       >TCONS_00000867
       >TCONS_00001442
       >TCONS_00001447
       >TCONS_00001528
       >TCONS_00001529
       >TCONS_00001668
       >TCONS_00001921

       file b
       >TCONS_00001528
       >TCONS_00001529
       >TCONS_00001668
       >TCONS_00001921
       >TCONS_00001922
       >TCONS_00001924

       file c
       >TCONS_00001529
       >TCONS_00001668
       >TCONS_00001921
       >TCONS_00001922
       >TCONS_00001924
       >TCONS_00001956
       >TCONS_00002048

       file d
       >TCONS_00001922
       >TCONS_00001924
       >TCONS_00001956
       >TCONS_00002048

すべてのファイルには2000を超える行が含まれ、最初の列に基づいてソートされます。

すべてのファイルで共通点を見つけたいです。 awk、grep、commを試しましたが、うまくいきません。

答え1

ファイルはすでにソートされているので:

comm -12 a b |
  comm -12 - c |
  comm -12 - d

commファイル間の行を見つけますcomm。デフォルトでは、commタブで区切られた3つの列を印刷します。

  1. 最初のファイルに固有の行、
  2. 2番目のファイルに固有の行、
  3. 両方のファイルに共通の行です。

-1、、、-2オプションを使用すると、その列-3を抑制します。したがって、レポートとcomm -12 a b公開行。 stdinを表すためにファイル名の代わりに使用できます。ab-

答え2

cat a b c d |sort |uniq -c |sed -n -e 's/^ *4 \(.*\)/\1/p'

答え3

comm入力として3つ以上のファイルが必要な場合は良いでしょう。そうでないため、値は表示されず、次のものを使用することをお勧めしますgrep

  • 事前ソートされた入力は必要ありません。
  • 出力列を抑制する必要はありません。
  • 命令はこのように短くて簡単ですcomm
grep -f a.txt b.txt | 
  grep -f - c.txt |
  grep -f - d.txt

-f <file>grepにパターンを検索するように指示し、 で見つかったすべての行が一致として出力される<file>ようにします。これはパイプの下に続くため、ANDの行は一致するパターンとして使用されます。パイプの最後に表示される唯一の出力は、各ファイルに表示される行です。a.txtb.txta.txtb.txtc.txt

答え4

使用幸せ(以前のPerl_6)

~$ raku -e 'my %h;  for dir(test => / file \w /) {   \
               %h{$_}++ for .lines.unique };         \
            .put if .value == 4 for %h;'

#OR

~$ raku -e 'my %h; my @a = dir(test => / file \w /);  \
            for @a { %h{$_}++ for .lines.unique };    \
            for %h { .put if .value == @a.elems };'

上記は、Perlシリーズのプログラミング言語であるRakuで書かれた答えです。簡単に言えば、Rakuのdir機能はローカルディレクトリをチェックし、ファイル名と一致する正規表現を抽出するために使用されます。ここでは、ファイル名の後に単語文字が付いていると仮定しますが、fileファイルを適切な正規表現(ワイルドカードパターンではない)と\w一致させることも簡単です。\.txt

上記の両方の答えはハッシュ%h値を宣言しました。ファイル名(実際に.IOはオブジェクト)を取得すると、line慎重に繰り返してfor同じ行を見るたびにハッシュキーを増やします。

value最初の答え(最後のステートメント)で一致がある場合、44つの入力ファイルすべてが行を返します。 2番目の答え(最後のステートメント)で一致するエントリvalue@a.elemsつまり入力ファイルの数(つまり、値が動的に設定されている)がある場合、その行が返されます。

入力例(注:ファイル名はfileAfileBなどです。また、 fileAOPの最初のファイルと比較して末尾に追加の行があります):

       fileA
       >TCONS_00000867
       >TCONS_00001442
       >TCONS_00001447
       >TCONS_00001528
       >TCONS_00001529
       >TCONS_00001668
       >TCONS_00001921
       >TCONS_00001922

       fileB
       >TCONS_00001528
       >TCONS_00001529
       >TCONS_00001668
       >TCONS_00001921
       >TCONS_00001922
       >TCONS_00001924

       fileC
       >TCONS_00001529
       >TCONS_00001668
       >TCONS_00001921
       >TCONS_00001922
       >TCONS_00001924
       >TCONS_00001956
       >TCONS_00002048

       fileD
       >TCONS_00001922
       >TCONS_00001924
       >TCONS_00001956
       >TCONS_00002048

出力例(すべてのキー/値の数を表示):

~$ raku -e 'my %h; for dir(test => / file \w /) { %h{$_}++ for .lines.unique }; .say for %h.sort: -*.value;'
>TCONS_00001922 => 4
>TCONS_00001668 => 3
>TCONS_00001921 => 3
>TCONS_00001924 => 3
>TCONS_00001529 => 3
>TCONS_00002048 => 2
>TCONS_00001528 => 2
>TCONS_00001956 => 2
>TCONS_00000867 => 1
>TCONS_00001442 => 1
>TCONS_00001447 => 1

出力例(.value == 4または行のみを表示.value == @a.elems):

~$ raku -e 'my %h; my @a = dir(test => / file \w /); for @a { %h{$_}++ for .lines.unique }; for %h { .key.put if .value == @a.elems};'
>TCONS_00001922

最後に、シェルワイルドカードを好む人のために、Rakuもこれを行うことができます。重要なことは、入力を正しく読み取る$*ARGFILESには動的変数を変換する必要があることを覚えておくことです。.handles

~$ raku -e 'my ($n,%h); for $*ARGFILES.handles -> $fh { $n++; %h{$_}++ for $fh.lines.unique }; for %h { .key.put if .value == $n };' file?
>TCONS_00001922

注:OPのテスト入力は、4つのファイルの間に共通の行がないため、難しいようです!したがって、最初のファイル(fileA)はポジティブコントロールを提供するように変更されました>TCONS_00001922

https://stackoverflow.com/a/68774047/7270649
https://docs.raku.org/routine/dir
https://docs.raku.org
https://raku.org

関連情報