tabela de matriz dividida com base na correspondência de célula para coluna

2

Eu tenho uma grande matriz separada por tabulações em um arquivo no Linux:

Name    ID  ABC12   ABCD12  ABCD123 ABCD1234
ABC12   123456  XX  YY  ZZ  JJ
ABC12   123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ

Eu quero dividir essa matriz em arquivos individuais com base na correspondência na primeira coluna, [é um arquivo grande, não pode contar os números das colunas]

resultado esperado:

Arquivo 1;

Name    ID  ABC12
ABC12   123456  XX
ABC12   123456  XX

Arquivo 2;

 
Name    ID  ABCD12
ABCD12  123456  YY
ABCD12  123456  YY

Arquivo 3;

Name    ID  ABCD123
ABCD123 123456  ZZ
ABCD123 123456  ZZ

Arquivo 4;

Name    ID  ABCD1234
ABCD1234    123456  JJ
ABCD1234    123456  JJ
    
por devbasic 18.08.2017 / 17:08

4 respostas

2

Solução completa do awk :

awk 'NR==1{ len=split($0,a_pos); for(i=1;i<=len;i++) a_keys[a_pos[i]]=i }
     NR>1{ if(!r[$1]++) { fn="file"++c; print "Name\tID\t"$1 > fn } 
           print $1,$2,$(a_keys[$1]) > fn 
     }' OFS='\t' file
  • len=split($0,a_pos) - divide a primeira linha em matriz de "chaves" (matriz a_pos é indexada com números inteiros)

  • for(i=1;i<=len;i++) a_keys[a_pos[i]]=i - invertendo a_pos no array a_keys , que será indexado com chaves de string (para processamento adicional)

  • fn="file"++c - construindo o nome do arquivo

Visualizando resultados:

for f in file[0-9]*; do (echo "$f"; cat "$f"; echo); done

A saída ( file1 , file2 , file3 e file4 consecutivamente):

file1
Name    ID  ABC12
ABC12   123456  XX
ABC12   123456  XX

file2
Name    ID  ABCD12
ABCD12  123456  YY
ABCD12  123456  YY

file3
Name    ID  ABCD123
ABCD123 123456  ZZ
ABCD123 123456  ZZ

file4
Name    ID  ABCD1234
ABCD1234    123456  JJ
ABCD1234    123456  JJ
    
por 18.08.2017 / 18:16
1

Você pode usar awk :

awk 'NR>1{if ($1!=p){N="file"++C; print "Name\tID\t"$1 >N};
             print $1,$2,$(C+2)>N}{p=$1}' infile.txt
    
por 18.08.2017 / 17:50
0

A maneira mais simples de pensar é salvar a primeira linha como uma variável e depois imprimir o resto conforme necessário. Isso, no entanto, requer salvar todo o arquivo de entrada na memória:

#!/bin/gawk -f
{
    if(NR==1){
        header[1]=$1;
        header[2]=$2;
        for(i=3;i<=NF;i++){
            header[$i]=i;
        }
    }
    else{
        data[$1][NR]=$2"\t"$(header[$1]);
    }
}
END{
    OFS="\t";
    for(i in data){
        print header[1],header[2],i > i".txt"
        for(k in data[i]){
            print i,data[i][k] >> i".txt"
        }
    }
}

Salve esse script como foo.awk , torne-o executável ( chmod a+x foo.awk ) e execute-o no seu arquivo:

foo.awk file
    
por 18.08.2017 / 17:50
0

Uso: ./split_matrix.awk input.txt

#!/usr/bin/awk -f

BEGIN {
    cnt = 1;
}

NR == 1 { 
    for(i = 3; i <= NF; i++) {
        headers[$i] = i;            
    }   
}
NR > 1 { 
    if( ! file_names[$1]) {
        file_names[$1] = cnt++;
        printf "%s %s %s\n", "Name", "ID", $1 > "file_"file_names[$1];
    }   
    printf "%s %s %s\n", $1, $2, $headers[$1] >> "file_"file_names[$1];
}

Teste

entrada

Name    ID  ABC12   ABCD12  ABCD123 ABCD1234
ABC12   123456  XX  YY  ZZ  JJ
ABC12   123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD12  123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD123 123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ
ABCD1234    123456  XX  YY  ZZ  JJ

output (use tail -n +1 -- file* para o nome do arquivo de impressão e o conteúdo do arquivo. Encontrei este truque aqui )

==> file_1 <==
Name ID ABC12
ABC12 123456 XX
ABC12 123456 XX

==> file_2 <==
Name ID ABCD12
ABCD12 123456 YY
ABCD12 123456 YY

==> file_3 <==
Name ID ABCD123
ABCD123 123456 ZZ
ABCD123 123456 ZZ

==> file_4 <==
Name ID ABCD1234
ABCD1234 123456 JJ
ABCD1234 123456 JJ
    
por 18.08.2017 / 19:03