1行あたりのフィールド数が可変である次の形式のファイルがあります。
NC_000001.11_NM_001005484.2 69270 234 69037 65565 69037
NC_000001.11_NM_001005484.2 69511 475 69037 65565 69037
NC_000001.11_NM_001005484.2 69761 725 69037 65565 69037
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144 942136 942410 942559 943253 943698 943908
各行に対して最初の4つのフィールドを印刷したいと思います。残りのフィールド($ 5〜NF)の場合、このフィールドの値が$ 4の値より小さい場合は、そのフィールドを印刷したいと思います。
出力例:
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
いくつかのawkオプションを試しましたが、すべて失敗しました。 awkに初めて触れてくれて助けてくれてありがとう。
答え1
出力でスペースを気にしない場合は、必要なものは次のとおりです。
$ cat tst.awk
{
out = $1 OFS $2 OFS $3 OFS $4
for (i=5; i<=NF; i++) {
if ( $i < $4 ) {
out = out OFS $i
}
}
print out
}
$ awk -f tst.awk file
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
column
必要に応じて、パイプを介して視覚的な位置合わせを実行できます。
$ awk -f tst.awk file | column -t
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
そうでなければ、出力の間隔が入力の間隔のように見えるようにしたい場合(つまり、最初の4つのフィールドは1つ以上の空白として見え、残りは2つ以上の空白として表されます)、一部の行には4つ以下の空白しかありません。 。フィールドを選択してPOSIX awkを使用します(文字クラスと正規表現スペース用)。
$ cat tst.awk
BEGIN { OFS="\t" }
match($0,/([^[:space:]]+[[:space:]]+){3}[^[:space:]]+/) {
out = substr($0,RSTART,RLENGTH)
for (i=5; i<=NF; i++) {
if ( $i < $4 ) {
out = out OFS $i
}
}
$0 = out
}
{ print }
$ 4以降のフィールドをタブで区切る必要がある場合:
$ awk -f tst.awk file
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
またはスペースで区切る必要がある場合:
$ awk -f tst.awk file | column -s$'\t' -t
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
上記は、入力のタブおよび/またはスペースの組み合わせに対して最初の4つのフィールド間のスペースを保持し、次に5番目以降のフィールドの前にタブを印刷します。これを使用して、同等のcolumn
アイテムが必要な場合は空白のままにできます。どちらも質問の入力と出力のように見えます。
out
上記のループで名前付きの新しい文字列を作成し、ループを変更するか、ループ内で変更するのではなく、ループの後に$0
一度割り当てます。これは、awkを変更するたびにそのフィールドに再構築する必要があり、awkを変更するたびに再分割する必要があるためです。フィールドに含まれるため、両方とも非効率的であり、フィールドの内容によって予期しないエラーが発生する可能性があるため、非常に特定の目的がない限り、ループ内で修正または修正しないでください。$0
$i
$i
$0
$0
$0
$0
$i
答え2
これはGNU Awk 5.1.0、API:3.0を使用してテストされました。split
これは、このソリューションの4番目のパラメータを使用すると、ここで使用されている構文と互換性のない他のバージョンでは機能しない可能性があるためです。
awk '{n=split($0, a, " ", b); line=""; for (i = 1; i <= n; i++) { if (i < 5 || a[i] < $4) line=(line a[i] b[i])}; print line; }' file.txt
説明する:
n=split($0, a, " ", b);
- 行全体($0
)を値(に保存されているa
)とスペース(に保存されているb
)に分割するので、元のファイルの形式を保存できます。保存された値は、n
各行に対して処理されるフィールドの数を提供します。split
配列a
とb
インデックスは両方とも1から始まります。line=""
- 空の文字列で始まるfor (i = 1; i <= n; i++)
- 各フィールドを繰り返し、インデックス1から分割してループを作成します。<=
最後の(n番目)フィールドも処理されることを部分的に保証します。if (i < 5 || a[i] < $4)
- 最初の4つのフィールドまたはフィールド値が4番目のフィールド(必要な条件)より小さい場合、条件はtrueです。line=(line a[i] b[i])
- 「if」条件要件を満たす古いフィールドとスペースと実際のフィールドとスペースを関連付けます。print line
-line
目的の出力を含む変数を印刷します。
答え3
これは、行の終わりから行の先頭まで(つまり、逆の順序で)フィールドを繰り返し、NF
フィールド番号()が4より大きい場合はフィールドを削除します。そしてこのフィールドの値は、$4
フィールド4()の値よりも大きいです。
$ awk '{
for (i=NF; i>=1; i--) {
if ((i > 4) && ($i >= $4)) {
$i=""
}
};
print
}' input.txt
NC_000001.11_NM_001005484.2 69270 234 69037 65565
NC_000001.11_NM_001005484.2 69511 475 69037 65565
NC_000001.11_NM_001005484.2 69761 725 69037 65565
NC_000001.11_NM_001385640.1 942155 20 942136 924432 925922 930155 931039 935772 939040 939272 941144
ところで、入力内容がスペースかタブで区切られているかはわかりません。各フィールドの間にスペースの代わりにタブ区切りの出力が必要な場合は、-v OFS='\t'
スクリプトを起動する単一引用符の前にawkコマンドを追加してください。例えば
awk -v OFS='\t' '...awk script here...' input.txt
ところで、awk は、フィールドが削除される前の位置に関係なく、出力行に多くの追加フィールド区切り文字を残します。これを削除するには、ステートメントの前に次の行を追加しますprint
。
$0=$0; $1=$1;
これにより、awkは入力行を再評価し、それをフィールドに再分割するように強制し、空のフィールドを効果的に削除します(FSから分割、フィールド区切り文字、デフォルトはスペースの数に制限なし)。 awkは実際に行のフィールドを削除する方法がないので、行を修正した後に強制的に削除する必要があるため、これは少しハッキングです。