次のように、20.000行を超えるテキストファイルがあります。
7 128550681 128550681 Intron:1:36:RETAINED-RETAINED;Transcript:NM_001135914.1;Gene:KCP:protein_coding 1 1 0 0
1 17718672 17718672 Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding 1 1 0 0
1 17718672 17718672 Intron:9:16:RETAINED-RETAINED;Transcript:NM_207421.4;Gene:PADI6:protein_coding 1 1 0 0
4 86035 86035 Exon:4:5:RETAINED;Transcript:NM_001286052.1;Gene:ZNF595:protein_coding 1 1 0 0
3 12942851 12942851 Intron:14:14:SKIPPED-ALTTENATIVE_3SS;Transcript:NM_001134382.2;Gene:IQSEC1:protein_coding 1 1 0 0
必要なのは、4番目の列にGene:genenameだけが含まれているため、出力は次のようになります。
7 128550681 128550681 Gene:KCP 1 1 0 0
1 17718672 17718672 Gene:PADI6 1 1 0 0
1 17718672 17718672 Gene:PADI6 1 1 0 0
4 86035 86035 Gene:ZNF595 1 1 0 0
3 12942851 12942851 Gene:IQSEC1 1 1 0 0
*問題はGene:genename
または:
で分割しようとしたときに;
が常に同じ場所にあるとは限らないことです
特定の列を選択する方法、パターンを含む行をgrepする方法など、非常に基本的なawk/sedを知っています。
次のawk
コマンドでこれを達成できました。
awk '{sub(/^.*;/,"",$4); print}' input
これにより、列4の最後の;
までのすべてが削除され、機能しない可能性があります(steeldriverのコメントを参照)。その場合は、質問を明確にして更新してください。
POSIXで定義された構成のみでawk
を使用すると、
awk 'match($4, /Gene:(.+)\:/){ $4=substr($4, RSTART, RLENGTH-1) }1' file
出力をもう少しきちんと揃えるには、出力を| column -t
にパイプします。これにより、列がタブで区切られます。行内のGene:genename
の位置がわからない場合は、awk
を変更して行内の任意のパターンを探し、4番目の列を必要な値で変更します。 $4
から$0
(行全体)に変更すると、問題なく動作するはずです。
awk 'match($0, /Gene:(.+)\:/){ $4=substr($0, RSTART, RLENGTH-1) }1' file
Perl -pale 's#(?:\H+\h+){3}\K\H+#($F[3] =~ /(?:^|;)(Gene:[^:]+)/)[0]#e' input-file.txt
°4番目のフィールドに遺伝子の位置が固定されていない場合は、上記のように実行できます。
°正規表現(?:\H+\h+){3}\K\H+
を使用して4番目のフィールドに焦点を合わせ、それをs///e
コマンドの代替部分で使用されている別の正規表現にすぐに置き換えます。
Perl:
_Perl -F'\h+' -lane '
for ( $F[3] ) {
my $a = index(";$_", ";Gene:" );
my $b = index(";$_", ":", $a+6 );
$_ = substr(";$_", $a+1, $b-$a-1);
}
print join "\t", @F;
' input-file.txt
_
出力:
_7 128550681 128550681 Gene:KCP 1 1 0 0
1 17718672 17718672 Gene:PADI6 1 1 0 0
1 17718672 17718672 Gene:PADI6 1 1 0 0
4 86035 86035 Gene:ZNF595 1 1 0 0
3 12942851 12942851 Gene:IQSEC1 1 1 0 0
$ 128550681 128550681 Gene:$$$ 1 1 0 0
_
説明:
Perl
オプション:-n
_ =>入力の行ごとの読み取りを呼び出します。-F
_ =>は_FS = horizontal whitespace
_になります。-a
_ =>各行をフィールドに分割し(FSは_-F
_オプションまたはデフォルトで単一のスペースによって設定されたものに基づいて))、配列_@F
_。-l
_ =>は_RS = ORS = "\n"
_になります。-e
_ =>以下はPerl
コードとして扱われ、各行、つまりレコードに適用されます。data structures
_関与:@F
_ =>レコードを分割して取得したフィールドが入力された配列。 0からインデックスが付けられます。したがって、_$F[3]
_はレコードの4番目のフィールドです。$a
_ =>は、4番目のフィールドの部分文字列_;Gene:
_の位置を保持します。$b
_ =>は、4番目のフィールドの部分文字列_:
_の位置を保持します。これは、_;Gene:
_の位置の6桁後に表示されます。 IOW、_:
_の後に2番目の_;Gene
_が見つかります。注:_$F[3]
_の位置はどこにでも配置できるため、検索文字列、つまり_Gene:
_にセミコロンを埋め込みます。したがって、4番目のフィールドの先頭にも配置できます。これは、その不測の事態に対処するためです。$_
_ =>は、ローカライズされたバージョンの_$F[3]
_をfor
ループ内に保持します。 substr
ビルトインは、_gene:...
_情報を抽出し、それを_$F[3]
_に保存します。$a,$b
_の変数定義の前のmy
修飾子は、スコープがfor
ループのみに制限されている字句変数としてマークします。for
ループ内の_$_
_は、現在のレコード/行を参照しません。 for
ループの期間中はオーバーロードされてローカライズされて_$F[3]
_になりました。GNU Sed:
_sed -Ee '
s/\S+/\n&\n/4
s/\n(.*;)?(Gene:[^:]+):.*\n/\2/
' input-file.txt
_
説明:
Gene:
_)を取り出し、その後_as many non colons we meet on the way before we hit the next colon
_を取り出します。列4を;
または:
で区切られた文字列のリストとして扱い、最初にそのフィールドを分割して、列全体を文字列Gene
と次の文字列(遺伝子名)に置き換えます。そして、必要なビットを見つけます。
$ awk -vOFS='\t' '{ split($4,a,"[;:]"); for (i in a) if (a[i]=="Gene") { $4 = a[i] ":" a[i+1]; break } } 1' file
7 128550681 128550681 Gene:KCP 1 1 0 0
1 17718672 17718672 Gene:PADI6 1 1 0 0
1 17718672 17718672 Gene:PADI6 1 1 0 0
4 86035 86035 Gene:ZNF595 1 1 0 0
3 12942851 12942851 Gene:IQSEC1 1 1 0 0