arquivo CSV: Agrupe e soma valores baseados no primeiro padrão de cada valor

1

Estou usando o bash para criar um script para localizar, agrupar e somar campos em um arquivo CSV. Cada linha terá campos separados por vírgula com cada campo seguindo uma convenção semelhante. Para cada campo separado por vírgulas, existe um valor numérico, depois um sinal de igual (=) e, em seguida, um valor alfanumérico. O "(número)=" pode ou não estar presente em uma linha e, se presente, a posição do campo pode variar, mas aparece apenas uma vez na linha. Além disso, o valor após o sinal de igual varia em comprimento.

Um exemplo do meu objetivo será o melhor. Arquivo CSV:

35=D,11=ABCD1,1=ABC,55=XYZ,38=100,40=P,18=M,54=1,59=0,10=111
35=D,11=ABCD2,1=ABC,55=XYZ,40=P,18=M,38=200,54=1,44=10.00,59=0,10=133
35=D,11=ABCD3,1=ABC,55=XYZ,40=P,18=M B,54=1,38=300,44=10.00,59=0,110=200,10=113
35=D,11=ABCD4,1=ABC,55=XYZ,38=400,40=P,18=M B F,54=1,44=10.00,59=0,110=300,10=144
35=D,11=ABCD5,1=ABC,55=ZYX,38=300,40=2,54=1,44=10.00,59=3,10=132
35=D,11=ABCD6,1=ABC,55=ZYX,38=100,40=1,18=C,54=2,59=3,10=131

Eu gostaria de ter um script que identificasse cada campo que começa com "38=" e, em seguida, some cada valor numérico que segue o "=" e agrupe por cada "55=". Haverá um "38=" e um "55=" em cada linha.

A saída usando o arquivo acima seria (o tipo é opcional):

55=XYZ 38=1000
55=ZYX 38=400
    
por Prev66 02.10.2018 / 22:04

3 respostas

1

steeldriver meio que me bateu nisso, mas eu inventei

perl -F'[=,]' -lane '
        %row = @F;
        $sum{$row{55}} += $row{38};
    }{ 
        print "$_ = $sum{$_}" for keys %sum
' file.csv
XYZ = 1000
ZYX = 400
    
por 02.10.2018 / 23:24
1

Aqui está uma solução awk .

awk -F, '{for(a=1;a++<=NF;){
          if($a~/^55=/){l=$a}
          if($a~/^38=/){b[l]+=substr($a,4)}
         }}END{for(x in b){print x,"38="b[x]}}' inp
  • for(a=1;a++<=NF;){ - percorre cada campo delimitado por vírgulas
  • if($a~/^55=/){l=$a} - se encontrarmos um campo que comece com 55= , armazene-o na variável l
  • if($a~/^38=/){b[l]+=substr($a,4)} - se encontrarmos um campo começando com 38= , pegue o valor depois de = e acumule-o na matriz b , usando a variável l como chave
  • }}END{for(x in b){print x,"38="b[x]}} - apenas imprima o conteúdo da matriz
por 02.10.2018 / 23:20
0

Que tal

awk -F, '
        {for (i=1; i<=NF; i++)  {split ($i, T, "=")
                                 if (T[1] == 55) IX = T[2]
                                 if (T[1] == 38) NM = T[2]
                                }
         SUM[IX] += NM
        }
END     {for (s in SUM) print "55=" s, "38=" SUM[s]
        }
' file
55=ZYX 38=400
55=XYZ 38=1000

Percorra todos os campos para encontrar os campos relevantes, divididos em T array, se 55 encontrado, extrair o índice, se 38 for encontrado, extrair summand. Após o loop, faça o somatório. Na seção END , exiba todos os valores somados com seus índices.

    
por 02.10.2018 / 23:33

Tags