ファイルの各行について、その値が他のフィールドの値より小さい場合、特定の列のフィールドをNFとして印刷します。

ファイルの各行について、その値が他のフィールドの値より小さい場合、特定の列のフィールドをNFとして印刷します。

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

おすすめ記事