次のようなファイルが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つの列を印刷します。
- 最初のファイルに固有の行、
- 2番目のファイルに固有の行、
- 両方のファイルに共通の行です。
-1
、、、-2
オプションを使用すると、その列-3
を抑制します。したがって、レポートとcomm -12 a b
公開行。 stdinを表すためにファイル名の代わりに使用できます。a
b
-
答え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.txt
b.txt
a.txt
b.txt
c.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
最初の答え(最後のステートメント)で一致がある場合、4
4つの入力ファイルすべてが行を返します。 2番目の答え(最後のステートメント)で一致するエントリvalue
、@a.elems
つまり入力ファイルの数(つまり、値が動的に設定されている)がある場合、その行が返されます。
入力例(注:ファイル名はfileA
、fileB
などです。また、 fileA
OPの最初のファイルと比較して末尾に追加の行があります):
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