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.txtsリストとして使用するにはどうすればよいですか?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

以下のスクリプトを使用すると、長い間うまく機能します。

k=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

関連情報