Hvordan formaterer du utdataene riktig med Awk printf-kommandoen?

Jeg har følgende fil:

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| 

Jeg prøver å formatere denne filen bruker awk printf for å ha følgende ønskede format:

  1. beholder samme rekkefølge av felt (venstre -> høyre)
  2. har komma «,» FS
  3. bare for l som tre felt ($ 5, $ 6, $ 7) som har alle tallene til å være 4 sifre, hvis mindre har et ledende null og bare to sifre etter punktet som 0123.12 eller 1234.10

skrev jeg følgende awk-kommando

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

men utdataene nedenfor har følgende problemer:

  1. er ikke i orden (venstre -> høyre)

  2. ikke har det ledende nullpunktet

    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 

Kan noen gi meg beskjed om hva som er feilen min, og hvordan jeg kan løse det?

Kommentarer

  • FYI, for kommaadskillelse uten å sitere hvert komma, kan du bruke 'BEGIN {OFS=","}' eller bare

—men det svarer ikke ' t ditt bredere spørsmål.

Svar

Du har feltene i riktig rekkefølge, men ditt første utskriftsuttalelse legger til en ny linje (Output Record Separator), så dataene dine er der, men bare pakket inn uventet.

Det andre problemet er at du forteller printf å bruke en bredde på 4; som inkluderer desimaltegnet og de to sifrene etter det, og etterlater bare ett for det ledende sifferet og ingen for noe polstring. Prøv å bruke 5 som bredde, slik at dataene dine er polstret opp til fire totaltall. Hvis du vil ha 4 sifre før desimaltegnet, endrer du bredden til 7 i stedet.

Dette er den korteste endringen jeg har gjort fra programmet ditt til noe som gir ut det jeg tror du ønsker:

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

Jeg kombinerte flere { } blokker i en, og kombinerte også utskriftsuttalelsene til en.

Hvis jeg skulle skrive awk-setningen din fra bunnen av, kan jeg gjøre noe sånt som dette:

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 

Det angir eksplisitt inndatafeltet , Output Field Separator, konverterer eksplisitt hvert av feltene alene, og skriver deretter ut de ønskede feltene, med OFS som skiller dem.

Kommentarer

  • Wow !!! Dette er flott, og jeg lærer mye. Setter virkelig pris på tiden din og den informative beskrivelsen 🙂 Best!

Svar

En måte å gjøre det på:

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

Kommentarer

  • @ Sato Katsura, Tnx mye det fungerer perfekt. Kan jeg be deg, vær så snill å forklare urskriptene dine for å forstå det! Jeg er ny i Awk. Trenger bare forklaringen på denne delen av skriptet ditt: {NF–; for (i = NF-2; i < = NF; i ++) $ i = sprintf ("% 07.2f ", $ i)} 1 '

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *