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

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| 

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

  1. manter a mesma ordem dos campos (esquerda -> direita)
  2. ter vírgula “,” FS
  3. apenas para l ast três campos ($ 5, $ 6, $ 7) tendo todos os números com 4 dígitos, se menos tiver 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 

entretanto, a saída abaixo tem os seguintes problemas:

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

  2. não tenha o zero à esquerda

    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 pode me informar qual é o meu erro e como corrigi-lo?

Comentários

  • Para sua informação, para separação de vírgulas sem aspas, você pode usar 'BEGIN {OFS=","}' ou apenas

—mas isso não ' responde à sua pergunta mais ampla.

Resposta

Você tem os campos na ordem certa, mas sua primeira instrução de impressão adiciona uma nova linha (separador de registro de saída), de modo que seus dados estão lá, mas apenas agrupados inesperadamente.

O segundo problema é que você está dizendo ao printf para usar uma largura de 4; isso inclui o ponto decimal e os dois dígitos após ele, deixando apenas um para o dígito inicial e nenhum para qualquer preenchimento. Tente usar 5 como largura, para que seus dados sejam preenchidos com até quatro números totais. Se você quiser 4 dígitos antes da vírgula decimal, altere a largura para 7 em vez disso.

Esta é a mudança mais curta que fiz em seu programa para algo que produz o que eu acho que você querer:

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

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

Se eu fosse escrever sua instrução awk do zero, eu 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 

Ele define explicitamente o separador de campo de entrada , o separador de campo de saída, converte explicitamente cada um dos campos por conta própria e, em seguida, imprime os campos desejados, com o OFS separando-os.

Comentários

  • Uau !!! Isso é ótimo e eu aprendo muito. Agradeço muito seu tempo e sua descrição informativa 🙂 Melhor!

Resposta

Uma maneira de fazer isso:

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

Comentários

  • @ Sato Katsura, Tnx muito funciona perfeitamente. Peço a você que explique seus scripts para entendê-los! Eu sou novo no Awk. Só precisa da explicação para esta parte do seu script: {NF–; para (i = NF-2; i < = NF; i ++) $ i = sprintf ("% 07.2f ", $ i)} 1 '

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *