awk:提取與第一行中的子字串相符的製表符分隔列

awk:提取與第一行中的子字串相符的製表符分隔列

我想從文字檔案(“columns.txt”)中提取製表符分隔的列,其中標題(第一行)與另一個文字檔案(“strings.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,如何從 中建立一個以逗號分隔的列名列表,並將其用作sstrings.txt的列表:namedcolcsvtool

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

或與csvcut/csvformat基於 Python 的類似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++對於第二個檔案的第一行,從雜湊中建立所有符合列名稱的索引列表
  • 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區塊中)之外。


解決評論中的問題:

若要始終複製前六列並剪下 處的列標題_,請變更

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

相關內容