awk: 最初の行の部分文字列に一致するタブ区切りの列を抽出します

awk: 最初の行の部分文字列に一致するタブ区切りの列を抽出します

ヘッダー (最初の行) が別のテキスト ファイル ("strings.txt") にリストされている特定の文字列と一致するテキスト ファイル ("columns.txt") からタブ区切りの列を抽出したいと思います。

「columns.txt」は次のようになります:

rs2438689   rs54666437   rs9877702046   rs025436779...
0           0            0              1
1           1            2              2 
0           1            2              0 
...         ...          ...            ...

「strings.txt」は次のようになります:

rs2438689
rs9877702046   
...

出力テキスト ファイル「output.txt」は次のようになります (タブ区切り)。

rs2438689   rs9877702046...
0           0              
1           2               
0           2               
...         ...    

awk でこれを行う方法について何か提案はありますか? ありがとうございます!

答え1

Awk の代わりに、 から列名のカンマ区切りリストを作成し、それをのstrings.txtのリストとして使用してはどうでしょうか。namedcolcsvtool

$ csvtool -t TAB -u TAB namedcol "$(paste -sd, < strings.txt)" columns.txt
rs2438689   rs9877702046
0   0
1   2
0   2
... ...

または、csvcut/csvformatPython ベースの と同様にcsvkit:

$ csvcut -tc "$(paste -sd, < strings.txt)" columns.txt | csvformat -T
rs2438689   rs9877702046
0   0
1   2
0   2
... ...

答え2

perl

$ perl -F'\t' -lane 'if(!$#ARGV){ $h{$_}=1 }
                     else{ @i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++;
                           print join "\t", @F[@i]}' strings.txt columns.txt
rs2438689   rs9877702046
0   0
1   2
0   2
  • if(!$#ARGV){ $h{$_}=1 }最初の入力ファイルでは、行の内容をキーとしてハッシュを作成します
  • @i = grep { $h{$F[$_]} == 1 } 0..$#F if !$c++2番目のファイルの最初の行では、ハッシュから一致するすべての列名のインデックスリストを作成します。
  • print join "\t", @F[@i]一致する列を印刷する

答え3

変更中前回の質問に対する私の解決策:

awk -F '\t' -f script.awk strings.txt columns.txt

どこscript.awkですか

BEGIN { OFS = FS }

FNR == NR {
    columns[$1] = 1
    next
}

FNR == 1 {
    for (i = 1; i <= NF; ++i)
        if ($i in columns)
            keep[i] = 1
}

{
    nf = split($0, fields, FS)
    $0 = ""
    j = 0

    for (i = 1; i <= nf; ++i)
        if (i in keep)
            $(++j) = fields[i]

    print
}

ここで、FNR == NRブロックはコマンドラインにリストされた最初のファイル()から読み取る間だけ実行されますstrings.txt。列の名前をキーとして配列に入力しますcolumns。残りのコードは次のとおりです。多かれ少なかれ現在の列が(ブロック内に)保持したい列であるかどうかを確認する部分を除いて、古いソリューションから変更されていませんFNR == 1


対処するコメント欄の質問:

最初の6列を常にコピーし、列ヘッダーを切り取るには_

FNR == 1 {
    for (i = 1; i <= NF; ++i)
        if ($i in columns)
            keep[i] = 1
}

の中へ

FNR == 1 {
    for (i = 1; i <= NF; ++i) {
        sub("_.*", "", $i)
        if (i <= 6 || $i in columns)
            keep[i] = 1
    }
}

答え4

以下のスクリプトを使用して実行します。長くなる可能性がありますが、問題なく動作しました。

か=wc -l file1| awk '{print $1}'

for ((i=1;i<=$k;i++));  do for j in `cat file2`; do awk -v i="$i" -v j="$j" '$i == j {x=NR+k}(NR<=x){print $i}' file1; done ; done>final.txt

z=`wc -l final.txt| awk '{print $1}'`

for ((i=1;i<=$z;i++)); do j=$(($i+3)); sed -n ''$i','$j'p' final.txt >file_starting_with_$i.txt; i=$j; done

paste file_starting_with*

出力

rs2438689   rs9877702046
0       0
1       2
0       2

関連情報