AWK - 关于列的问题

AWK - 关于列的问题

我有个问题。我试图自己解决这个问题,但似乎我太新了,无法awk让它发挥作用。

假设我们有一个文件(例如database.txt)(值以制表符分隔):

NA64715 YU24921 MI84612 MI98142 NA94732    
3241531 4957192 4912030 6574918 0473625     
0294637 9301032 8561730 8175919 8175920     
9481732 9359032 8571930 8134983 9385130     
9345091 9385112 2845830 4901742 3455141     

在一个单独的文件(例如populations.txt)中,我有关于哪个 ID 属于哪个组的信息,例如:

NA64715 Europe    
YU24921 Europe    
MI84612 Asia    
MI98142 Africa    
NA94732 Asia    

我需要做的是强制awk为所有组(欧洲、亚洲、非洲)创建包含列的单独文件。我需要处理的文件很大,所以我不能简单地对列进行计数和编号并以简单的方式完成。我需要awk检查哪个 ID 属于哪个人口(欧洲等),然后在数据库文件中找到该特定列,然后将整个列复制到一个新文件(对于所有人口来说是分开的)。

结果应该如下所示:

文件1(europe.txt):

NA64715 YU24921     
3241531 4957192     
0294637 9301032     
9481732 9359032    
9345091 9385112      

文件2 ( asia.txt)

MI84612 NA94732    
4912030 0473625    
8561730 8175920    
8571930 9385130    
2845830 3455141    

文件 3 ( africa.txt)

MI98142     
6574918    
8175919    
8134983    
4901742    

谁能帮我解决这个问题吗?

答案1

这可以一次性遍历文件,并且不需要将整个文件存储在内存中。它确实为每个目标文件保留打开的文件描述符。

awk -F '\t' '
    NR==FNR {population[$1]=$2; next}
    FNR==1 {
        for (i=1; i<=NF; i++) {
            destination[i] = population[$i] ".txt"
        }
    }
    {
        delete separator
        for (i=1; i<=NF; i++) {
            printf "%s%s", separator[destination[i]], $i > destination[i]
            separator[destination[i]] = FS
        }
        for (file in separator) {
            printf "\n" > file
        }
    }
' populations.txt database.txt

答案2

我相信这不是最好的方法,因为我们需要读取database.txt的次数与我们拥有的区域加一一样多。不幸的是,我没有想到另一种方式。

  1. 转置数据库.txt:

    awk '{for(i=1;i<=NF;i++){a[NR,i]=$i}}NF>p{p=NF}END{for(j=1;j<=p;j++ ){str=a[1,j];for(i=2;i<=NR;i++){str=str" "a[i,j];}print str}}' 数据库.txt > 数据库.tmp

更具可读性(相同的命令):

awk '
{ 
    for (i=1; i<=NF; i++)  {
        a[NR,i] = $i
    }
}
NF>p { p = NF }
END {    
    for(j=1; j<=p; j++) {
        str=a[1,j]
        for(i=2; i<=NR; i++){
            str=str" "a[i,j];
        }
        print str
    }
}' database.txt > database.tmp

2.读取带有ids的文件并从转置的database.tmp中grep所有id:

while read id region ; do grep -m 1 $id database.tmp >> $region.txt.tmp ; done < population.txt

3.将所有region.txt.tmp文件转置为您需要的形式:

for region_file in *txt.tmp ; do awk '{for(i=1;i<=NF;i++){a[NR,i]=$i}}NF>p{p=NF}END{for(j=1;j<=p;j++){str=a[1,j];for(i=2;i<=NR;i++){str=str" "a[i,j];}print str}}' $region_file > ${region_file%.tmp} ; done

4.删除所有临时文件

相关内容