Processamento de texto usando sed / awk / perl

0

Eu tenho um texto como esse padrão em várias linhas. Posso agrupar apenas os valores e o nome em uma única linha?

ABCDEFG_10_node10:2154  ABCDEFG_10_node10:54
ABCDEFG_10_node10:2254  ABCDEFG_10_node10:64
ABCDEFG_10_node10:410 ABCDEFG_10_node10:10
ABCDEFG_10_node10:210 ABCDEFG_10_node10:10 
ABCDEFG_10_node10:365
ABCDEFG_10_node10:890
ABCDEFG_10_node10:741
XXYZZ_71_node2:24: XXYZZ_71_node2:504:
X3y5z_53_node1:664: X3y5z_53_node1:990:
RCTY_11_node2:224: RCTY_11_node2:234:

Resultado esperado:

ABCDEFG_10_node10: 2154,2254,410,210,365,890,741,54,64,10,10
XXYZZ_71_node2: 24,504
X3y5z_53_node1: 664,990
RCTY_11_node2: 224,234

Estou no AIX. Como posso fazer isso?

    
por satsensort 06.10.2017 / 12:38

3 respostas

5

Uma abordagem Perl (assumindo que a ordem não é importante):

$ perl -lne 'while(/(\w+):(\d+)/g){
                push @{$k{$1}},$2
             } 
             END{
                print "$_: " . join ",", @{$k{$_}} for keys %k
             }' file 
ABCDEFG_10_node10: 2154,54,2254,64,410,10,210,10,365,890,741

Isso lê o arquivo de entrada linha a linha ( -ln ) e executa o script fornecido por -e nele. O while(/(\w+):(\d+)/g) coletará todas as instâncias de espaços não brancos, seguidas por : e, em seguida, mais espaços não brancos. Como eles estão sendo capturados entre parênteses, o $1 será o nome e o $2 o valor. Estes são então colocados em um hash de arrays (hash %k , cujos valores são arrays). Finalmente, imprimimos cada chave do hash (os nomes) junto com o array de seus valores, unidos por , .

Se você valoriza a concisão, você pode escrever o acima como um verso:

perl -lne 'while(/(\S+):(\S+)/g){push @{$k{$1}},$2}}{$"=",";print"$_: @{$k{$_}}" for keys%k' file

legibilidade passada:

perl -nE'push@{$k{$1}},$2while/(\w+):(\d+)/g}{$"=",";say"$_: @{$k{$_}}"for keys%k' file
    
por 06.10.2017 / 13:03
3
Solução

Awk :

awk -F':|[[:space:]]+' '{ 
         a[$1]=a[$1]? a[$1]","$2:$2; if(NF==4) b[$3]=b[$3]? b[$3]","$4:$4 
     }
     END{ for(i in a) printf "%s: %s%s\n",i,a[i],(i in b)? ","b[i]:"" }' file
  • -F':|[[:space:]]+' - separador de campo complexo

  • a[$1]=a[$1]? a[$1]","$2:$2 - valores de agrupamento para cada nome exclusivo ABCDEFG...

  • if(NF==4) b[$3]=b[$3]? b[$3]","$4:$4 - se houver uma seção adicional do lado direito - agrupe os valores na matriz adicional b

A saída:

ABCDEFG_10_node10: 2154,2254,410,210,365,890,741,54,64,10

----------

Se a ordem dos valores não for importante, a abordagem acima pode ser ligeiramente simplificada:

awk -F':|[[:space:]]+' '{ 
        a[$1]=a[$1]? a[$1]","$2:$2; if(NF==4) a[$3]=a[$3]? a[$3]","$4:$4 
     }
     END{ for(i in a) print i":",a[i] }' file
    
por 06.10.2017 / 13:01
1
awk '{ for (i=1;i<=NF;i++) { split($NF,arr,":");if (dat[arr[1]]=="") { dat[arr[1]]=arr[2] } else { dat[arr[1]]=dat[arr[1]]","arr[2] } } } END { for ( i in dat ) { print i": "dat[i] } }' filename

Uma solução alternativa do awk para Roman onde nós pegamos cada dado delimitado por espaço e depois dividimos os dados usando a função split na matriz arr baseada no caractere: Nós então construímos uma matriz chaveada na string ABC etc com a seqüência de números a serem impressos. Em seguida, percorremos esse array (dat) construindo uma string começando com a chave junto com: e a string. Isso é então impresso.

    
por 06.10.2017 / 13:40