Como formatar corretamente a saída com o comando awk printf?

3

Eu tenho o seguinte arquivo:

echo filename
    dfT08r352|30.5|2010/06/01|2016/08/29|2281|6.24503764544832|74.9404517453799|
    zm00dr121|37|2008/03/05|2011/09/12|1285.95833333333|3.52076203513575|42.249144421629|
    ccvd00121|41.6|2008/03/05|2012/03/05|1461|4|48|
    sddf00121|39.6|2008/03/05|2012/09/10|1649.95833333333|4.51733972165184|54.208076659822|
    fttt00121|41|2008/03/05|2013/09/16|2020.95833333333|5.53308236367785|66.3969883641342|
    ghhyy0121|42.2|2008/03/05|2014/03/18|2203.95833333333|6.03410905772302|72.4093086926762|

Eu estou tentando formatar este arquivo usando awk printf para ter o seguinte formato desejado:

  1. mantenha a mesma ordem de campos (à esquerda - > à direita)
  2. tem vírgula "," FS
  3. apenas para o ast três campos ($ 5, $ 6, $ 7) com todos os os números têm 4 dígitos, se menos tiverem um zero à esquerda e apenas 2 dígitos após o ponto como 0123.12 ou 1234.10

Eu escrevi o seguinte comando awk

awk -F"|" '{print $1","$2","$3","$4}{format = "%04.2f,%04.2f,%04.2f,"}{printf format, $5,$6,$7}' filename

no entanto, a saída abaixo apresenta os seguintes problemas:

  1. não está em ordem (à esquerda - > à direita)

  2. não tem o zero inicial

    dfT08r352,30.5,2010/06/01,2016/08/29
    2281.00,6.25,74.94,zm00dr121,37,2008/03/05,2011/09/12
    1285.96,3.52,42.25,ccvd00121,41.6,2008/03/05,2012/03/05
    1461.00,4.00,48.00,sddf00121,39.6,2008/03/05,2012/09/10
    1649.96,4.52,54.21,fttt00121,41,2008/03/05,2013/09/16
    2020.96,5.53,66.40,ghhyy0121,42.2,2008/03/05,2014/03/18
    

Alguém por favor pode me dizer qual é o meu erro e como corrigi-lo?

    
por Daniel 20.12.2016 / 21:30

2 respostas

2

Você tem os campos na ordem correta, mas sua primeira declaração de impressão adiciona uma nova linha (Output Record Separator), para que seus dados estejam lá, mas acabaram sendo quebrados inesperadamente.

A segunda questão é que você está dizendo ao printf para usar uma largura de 4; que inclui o ponto decimal e os dois dígitos depois dele, deixando apenas um para o dígito principal e nenhum para qualquer preenchimento. Tente usar 5 como a largura, para que seus dados sejam preenchidos até quatro números totais. Se você quiser 4 dígitos antes do ponto decimal, altere a largura para 7 em vez disso.

Esta é a menor mudança que fiz no seu programa para algo que gera o que eu acho que você quer:

awk -F"|" '{
  format = "%05.2f,%05.2f,%05.2f"; 
  print $1","$2","$3","$4"," sprintf(format, $5,$6,$7)}' filename

Combinei vários blocos de { } em um e também combinei as instruções de impressão em uma.

Se eu fosse escrever sua instrução awk do zero, poderia fazer algo assim:

awk -v FS=\| -v OFS=, '{
  $5=sprintf("%05.2f", $5); 
  $6=sprintf("%05.2f", $6); 
  $7=sprintf("%05.2f", $7); 
  print $1,$2,$3,$4,$5,$6,$7}' filename

Define explicitamente o Separador de Campos de Entrada, o Separador do Campo de Saída, converte explicitamente cada um dos campos por si próprio e imprime os campos desejados, com o OFS separando-os.

    
por 20.12.2016 / 22:15
2

Uma maneira de fazer isso:

awk -F \| -v OFS=, '{ NF--; for(i = NF-2; i <= NF; i++) $i = sprintf("%07.2f", $i) } 1' filename
    
por 20.12.2016 / 22:04