AWK - uma pergunta sobre colunas

5

Eu tenho uma pergunta. Eu estava tentando lidar com isso sozinho, mas parece que eu sou muito novo em awk para fazer isso funcionar.

Vamos supor que temos um arquivo (por exemplo, database.txt) (os valores são separados por tabulações):

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     

Em um arquivo separado (por exemplo, populations.txt ), tenho informações sobre qual ID pertence a qual grupo, por exemplo:

NA64715 Europe    
YU24921 Europe    
MI84612 Asia    
MI98142 Africa    
NA94732 Asia    

O que preciso fazer é forçar awk a criar arquivos separados com colunas para todos os grupos (Europa, Ásia e África). O arquivo que eu preciso trabalhar é enorme, então eu não posso simplesmente contar e numerar colunas e fazer do jeito mais fácil. Eu preciso de awk para verificar qual ID pertence a qual população (Europa etc.), então encontrar aquela coluna em particular em um arquivo de banco de dados, e então copiar uma coluna inteira para um novo arquivo (separado para todas as populações).

O resultado deve ser parecido com:

Arquivo 1 ( europe.txt ):

NA64715 YU24921     
3241531 4957192     
0294637 9301032     
9481732 9359032    
9345091 9385112      

Arquivo 2 ( asia.txt )

MI84612 NA94732    
4912030 0473625    
8561730 8175920    
8571930 9385130    
2845830 3455141    

Arquivo 3 ( africa.txt )

MI98142     
6574918    
8175919    
8134983    
4901742    

Alguém pode me ajudar com esse problema?

    
por Lalilienne 05.06.2013 / 16:41

2 respostas

7

Isso funciona de uma só vez no arquivo e não precisa armazenar todo o arquivo na memória. Mantém descritores de arquivos abertos para cada arquivo de destino.

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
    
por 05.06.2013 / 18:36
3

Eu acredito que este não é o melhor caminho, já que precisamos ler um banco de dados.txt quantas vezes forem as regiões que temos mais uma. Infelizmente o outro caminho não veio à minha mente.

  1. Transponha o banco de dados.txt:

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

um pouco mais legível (o mesmo comando):

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. ler arquivo com ids e grep todos os ids do banco de dados transposto.tmp:

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

3. transponha todo o arquivo region.txt.tmp para um formulário que você precisa:

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. remova todos os arquivos temporalizados

    
por 05.06.2013 / 17:13

Tags