web-dev-qa-db-ja.com

特定の文字列が含まれる行のグループを印刷します

次のようなファイル(file 1)があります。

>C 0
0   4231aa, >A6_03412... at 1:4226:1:4240/95.44%
1   4240aa, >A5_01600... *
>C 1
0   4159aa, >FG1_03697... *
>C 2
0   3942aa, >A3_03045... at 1:3942:1:3945/96.50%
1   3945aa, >A4_03199... *
2   3942aa, >A7_02989... at 1:3942:1:3945/92.11%
3   3941aa, >A6_03202... at 1:1:1:1/96.35%

2つの>Cの間の部分をサブグループと見なします。したがって、たとえばこれはサブグループです

 >C 0
 0  4231aa, >A6_03412... at 1:4226:1:4240/95.44%
 1  4240aa, >A5_01600... *

次に、サブグループ内に文字列を含む別のファイル(file 2)があります。

A6_03412
A4_03199
.....

file 2の文字列を含むすべてのサブグループを印刷します。したがって、file 2には上記の文字列があるだけで、出力は次のようになります。

>C 0
0   4231aa, >A6_03412... at 1:4226:1:4240/95.44%
1   4240aa, >A5_01600... *
>C 2
0   3942aa, >A3_03045... at 1:3942:1:3945/96.50%
1   3945aa, >A4_03199... *
2   3942aa, >A7_02989... at 1:3942:1:3945/92.11%
3   3941aa, >A6_03202... at 1:1:1:1/96.35%

これは難しいことですが、bashスクリプトを使用してこれを行う方法はありますか?

4
efrem

Perlとgrepを使用した2部構成のソリューション:

Perl -pe 's/^>C \d+$/\0$&/' file1 | grep -zFf file2
  • >C <some number>はグループを区切るので、それに一致し、各グループの前にASCII nul文字(\0)]を挿入します。
  • そうすれば、ファイルからパターンを読み取りながら(-z)、NULで区切られた行(-f file2)を処理するgrepの機能を利用できます。

Awkでは、レコードセパレータとして>Cを使用し、各レコードの前にNULを出力することにより、同様のことを行います。

awk -v RS='>C ' '{printf "\0>C %s", $0}' foo | grep -zFf ba
4
muru

Pythonアプローチ:

#!/usr/bin/env python2
with open('file_1') as f_1, open('file_2') as f_2:
    f_1_subgroups = f_1.read().split('>C')
    f_2_lines = [line.rstrip() for line in f_2]
    for subgroup in f_1_subgroups:
        for line in f_2_lines:
            if line in subgroup:
                print '>C' + subgroup

ここでは、最初に区切り文字>Cを使用して「file_1」をサブグループに分割し、次にサブグループ内の「file_2」の行を検索しました。見つかった場合、サブグループを印刷しました。

リスト内包表記の使用:

#!/usr/bin/env python2
with open('file_1') as f_1, open('file_2') as f_2:
    f_1_subgroups = f_1.read().split('>C')
    f_2_lines = [line.rstrip() for line in f_2]
    print ''.join(['>C' + subgroup for line in f_2_lines for subgroup in f_1_subgroups if line in subgroup])
0
heemayl