awk comando para delimitar a segunda coluna

0

Eu tenho um arquivo com dados no formato abaixo

Item1|keys,books,helmet,handle,
Item2|Bike,
Item3
Item4|Tyre,brakes,headlight,clamps,rollergrip,
Item5|Nails,hammers,

Eu queria que os dados acima fossem convertidos para o formato abaixo

Item1|keys
Item1|books
Item1|helmet
Item1|handle
Item2|Bike
Item3
Item4|Tyre
Item4|brakes
Item4|headlight
Item4|clamps
Item4|rollergrip
Item5|Nails
Item5|hammers

Eu estava tentando conseguir isso usando o comando cut, embora estivesse funcionando bem. Eu queria saber se isso pode ser feito usando o comando awk. Como se o tamanho do arquivo de entrada ficar maior, isso deve ser complicado.

    
por ramp 20.06.2017 / 16:56

3 respostas

1
sed -e 's/,$//' -e '/^[^|]*$/s/$/|/' file.in |
awk -F'[|,]' -vOFS='|' '{ for (i = 2; i <= NF; ++i) { print $1, $i } }'

O sed faz um pouco de pré-processamento dos dados de entrada. Ele remove as vírgulas à direita no final de cada linha ( -e 's/,$//' ) e, se uma linha não contiver um símbolo de pipe, ela adicionará uma ao final ( -e '/^[^|]*$/s/$/|/' ).

Os dados do exemplo são transformados no seguinte pelo filtro sed :

Item1|keys,books,helmet,handle
Item2|Bike
Item3|
Item4|Tyre,brakes,headlight,clamps,rollergrip
Item5|Nails,hammers

O script awk leva isso e interpreta cada linha como um conjunto de campos separados por um símbolo de pipe ou uma vírgula ( -F'[|,]' ). Para cada linha de entrada, ela irá emparelhar repetidamente o primeiro campo com cada um dos outros campos e gerá-los. Cada par de campos na saída é separado por um símbolo de pipe ( -vOFS='|' ).

O resultado é

Item1|keys
Item1|books
Item1|helmet
Item1|handle
Item2|Bike
Item3|
Item4|Tyre
Item4|brakes
Item4|headlight
Item4|clamps
Item4|rollergrip
Item5|Nails
Item5|hammers
    
por 20.06.2017 / 17:16
1
Solução

awk :

awk -F'|' 'NF>1 && $2~/[^,]+,[^,]*/{ 
           len=split($2,a,","); 
           for(i=1;i<=len;i++) { 
               if(a[i]!="") print $1,a[i] 
           } 
           next }1' OFS='|' file

A saída:

Item1|keys
Item1|books
Item1|helmet
Item1|handle
Item2|Bike
Item3
Item4|Tyre
Item4|brakes
Item4|headlight
Item4|clamps
Item4|rollergrip
Item5|Nails
Item5|hammers

Detalhes :

  • -F'|' - separador de campos

  • NF>1 && $2~/[^,]+,[^,]*/ - considera pelo menos dois campos com valores separados por vírgula no segundo campo

  • len=split($2,a,",") - divide o segundo campo no array a pelo separador , . A variável len é atribuída com o tamanho da matriz (número de partes)

  • for(i=1;i<=len;i++) iterando pelos " blocos "

  • if(a[i]!="") print $1,a[i] - imprime cada sequência relacionada, exceto valores vazios

por 20.06.2017 / 17:06
1

Outra awk versão

  • define o separador de campo como | ou ,
  • se o registro tiver menos de dois campos, imprima-o como está
  • faça um loop sobre todos os campos 2 para NF-1 printing $1 e $i (isso ignora o $NF vazio causado pela vírgula final

ou seja,

$ awk 'NF<2 ; {for (i=2;i<NF;i++) print $1,$i}' FS='[|,]' OFS='|' file
Item1|keys
Item1|books
Item1|helmet
Item1|handle
Item2|Bike
Item3
Item4|Tyre
Item4|brakes
Item4|headlight
Item4|clamps
Item4|rollergrip
Item5|Nails
Item5|hammers
    
por 20.06.2017 / 17:35