4列のタブで区切られたファイルがあり、最後の列に重複することがあります。以下は文書から抜粋したものです。
chr7 116038644 116039744 GeneA
chr7 116030947 116032047 GeneA
chr7 115846040 115847140 GeneA
chr7 115824610 115825710 GeneA
chr7 115801509 115802609 GeneA
chr7 115994986 115996086 GeneA
chrX 143933024 143934124 GeneB
chrX 143933119 143934219 GeneB
chrY 143933129 143933229 GeneC
列の各重複値セットに対して、次のように変換したいと思います(列の重複しない値に実際に触れることなく)。
chr7 116038644 116039744 GeneA-1
chr7 116030947 116032047 GeneA-2
chr7 115846040 115847140 GeneA-3
chr7 115824610 115825710 GeneA-4
chr7 115801509 115802609 GeneA-5
chr7 115994986 115996086 GeneA-6
chrX 143933024 143934124 GeneB-1
chrX 143933119 143934219 GeneB-2
chrY 143933129 143933229 GeneC
または、Bashawk
ループを使用してこれをどのように実行できますか?sed
for
答え1
この試み
awk -F'\t' -v OFS='\t' '{$4=$4 "-" (++count[$4])}1' file.tsv
これは、4番目のフィールド値の各発生をカウンタの配列count
(4番目のフィールドの値が「インデックス」として使用されます)に格納し、そのカウンタの事前に増加した値を4番目のフィールドとダッシュに追加します。
上記の「簡単な」例には1つの欠点があります。ファイルに一度だけ表示される列4の値に明確性番号を追加することもできます。これを抑制するには、次のようなデュアル転送アプローチを使用できます(読みやすくするためにコマンドを2行に分割\
)。
awk -F'\t' -v OFS='\t' 'NR==FNR{f[$4]++}\
NR>FNR{if (f[$4]>1) {$4=$4 "-" (++count[$4])}; print}' file.tsv file.tsv
処理するファイルが記録されています。二重パラメータとして使用されるため、2回読み取られます。
- 最初の読み取り(グローバル
FNR
行カウンターと同じファイル別のNR
行カウンターで表されます)では、列4の各固有値がファイルに表示される頻度を計算し、それを配列に保存しますf
。 - 2番目にファイルを読み取るときは、「簡単な」方法などの実際のテキスト処理を実行し、発生カウンタを列4に追加します。ただし、最初のパスで見つかった総発生回数が1より大きい場合にのみ該当します。
このアプローチは、ファイル全体のバッファリングを防ぎ、ファイルが非常に大きい場合に利点となります。もちろん、ファイルを2回読み取るため、処理時間が長くなります。
通常、テキスト処理にシェルループを使用する必要はほとんどありません。awk
たとえば、ループ操作をより効率的な方法で独自に実行できるためです。
答え2
例に示すように、入力ファイルが4番目の列にグループ化されているとします。
$ cat tst.awk
$NF != prev {
prt()
cnt = 0
prev = $NF
}
{ rec[++cnt] = $0 }
END { prt() }
function prt() {
for (i=1; i<=cnt; i++) {
print rec[i] (cnt > 1 ? "-"i : "")
}
}
。
$ awk -f tst.awk file
chr7 116038644 116039744 GeneA-1
chr7 116030947 116032047 GeneA-2
chr7 115846040 115847140 GeneA-3
chr7 115824610 115825710 GeneA-4
chr7 115801509 115802609 GeneA-5
chr7 115994986 115996086 GeneA-6
chrX 143933024 143934124 GeneB-1
chrX 143933119 143934219 GeneB-2
chrY 143933129 143933229 GeneC
答え3
これは「-のみ追加されます。数字その値が一意でない場合は、指定された(ターゲット)フィールド(例では4番目のフィールド)に追加されます。また、入力がターゲット列に対してソートされていない場合も処理し、入力列の数に関係なく機能します。
次のAWKスクリプトはターゲットフィールドで入力をソートする必要があるため、パイプを使用して元の行の番号を付け(現在)、5番目のフィールド(最初のフィールドは先行番号)にソートし、非行にサフィックスを追加します。 5番目のフィールドの一意の値で、行を元の順序に戻し、先行番号を削除します。
nl file | sort -b -t '<TAB>' -k5,5 -k1n,1n | awk -F '\t' -v OFS='\t' -v kf=5 '
function prn () {
for (i = 1; i <= nfl; i++) {
if (i == kf)
printf("%s", prc[i] ( sw || cnt[prc[i]] ? "-"++cnt[prc[i]] : ""))
else
printf("%s", prc[i])
printf("%s", (i == nfl ? ORS : OFS))
}
}
NR > 1 {
sw = ($kf == prc[kf])
prn()
}
{
nfl = split($0, prc)
}
END {
if (NR > 0)
prn()
} ' | sort -k1n,1n | cut -f 2-
このAWKスクリプトのポイントは印刷することです。より早いkf
行の最初のフィールドが現在の行のフィールドと同じであること、または最初のフィールドがkf
複数回発生したことを確認します。どちらの場合も、kf
最初のフィールドは追加された回数で印刷されます。
明確にしたい列の実際の位置を反映するように-v kf=5
(およびキー)を調整する必要があります。-k5,5
sort
次の例(行を混ぜて列を追加した例)を考えると、次のようになりますfile
。
chr7 116038644 116039744 GeneA foo
chrX 143933024 143934124 GeneB foo
chr7 116030947 116032047 GeneA foo
chr7 115824610 115825710 GeneA foo
chrY 143933129 143933229 GeneC foo
chr7 115994986 115996086 GeneA foo
chrX 143933119 143934219 GeneB foo
chr7 115801509 115802609 GeneA foo
chr7 115846040 115847140 GeneA foo
出力は次のとおりです。
chr7 116038644 116039744 GeneA-1 foo
chrX 143933024 143934124 GeneB-1 foo
chr7 116030947 116032047 GeneA-2 foo
chr7 115824610 115825710 GeneA-3 foo
chrY 143933129 143933229 GeneC foo
chr7 115994986 115996086 GeneA-4 foo
chrX 143933119 143934219 GeneB-2 foo
chr7 115801509 115802609 GeneA-5 foo
chr7 115846040 115847140 GeneA-6 foo
答え4
簡単な2段階のawk
コマンド:
$ awk -F '\t' '
BEGIN { OFS=FS }
pass == 1 { count[$4]++; next }
count[$4] > 1 { $4 = $4 "-" ++number[$4] }; 1' pass=1 file pass=2 file
chr7 116038644 116039744 GeneA-1
chr7 116030947 116032047 GeneA-2
chr7 115846040 115847140 GeneA-3
chr7 115824610 115825710 GeneA-4
chr7 115801509 115802609 GeneA-5
chr7 115994986 115996086 GeneA-6
chrX 143933024 143934124 GeneB-1
chrX 143933119 143934219 GeneB-2
chrY 143933129 143933229 GeneC
これは、入力ファイルがタブで区切られていると仮定します。-F '\t'
そうでない場合は、編集または削除してください。
ファイルを最初にナビゲートすると、連想配列はcount
4列目の各遺伝子名の発生回数で埋められます。
ファイルを2回目に渡すときにデータセットに複数の遺伝子名が表示される場合(ファイルを介して最初に渡されると)、ダッシュと数字が遺伝子名の末尾に追加されます。
counter
追加された数字は、配列と同様に遺伝子名で入力される別のカウンタです。