Jak poprawnie sformatować wyjście za pomocą polecenia Awk printf?

Mam następujący plik:

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| 

Próbuję sformatować ten plik używając awk printf, aby mieć następujący pożądany format:

  1. zachowaj tę samą kolejność pól (lewo -> prawo)
  2. przecinek „,” FS
  3. tylko dla l trzech pól (5 USD, 6 USD, 7 USD) , w których wszystkie liczby mają 4 cyfry, jeśli mniej ma początkowe zero i tylko 2 cyfry po przecinku, jak 0123.12 lub 1234.10

Napisałem następujące polecenie awk

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

jednak poniższe dane wyjściowe mają następujące problemy:

  1. nie jest w porządku (od lewej do prawej)

  2. nie mają początkowego zera

    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 

Czy ktoś może mi powiedzieć, jaki jest mój błąd i jak go naprawić?

Komentarze

  • Do Twojej wiadomości, aby oddzielić przecinki bez cytowania każdego przecinka, możesz użyć 'BEGIN {OFS=","}' lub po prostu

– ale to nie ' nie odpowiada na twoje szersze pytanie.

Odpowiedź

Masz pola we właściwej kolejności, ale pierwsza instrukcja print dodaje nowy wiersz (separator rekordów wyjściowych), więc dane są tam, ale po prostu nieoczekiwanie zawijane.

Drugą kwestią jest to, że mówisz printf, aby używał szerokości 4; który zawiera przecinek dziesiętny i dwie cyfry po nim, pozostawiając tylko jedną cyfrę wiodącą i żadną dla wypełnienia. Spróbuj użyć 5 jako szerokości, aby dane były uzupełnione do czterech liczb łącznie. Jeśli chcesz mieć 4 cyfry przed kropką dziesiętną, zamiast tego zmień szerokość na 7.

To jest najkrótsza zmiana, jaką wprowadziłem w twoim programie na coś, co wyświetla to, co myślę chcesz:

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

Połączyłem wiele bloków { } w jeden, a także połączyłem instrukcje print w jeden.

Gdybym miał napisać twoją instrukcję awk od zera, mógłbym zrobić coś takiego:

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 

To jawnie ustawia separator pól wejściowych , Separator pól wyjściowych, jawnie konwertuje każde z pól na własną rękę, a następnie drukuje żądane pola, oddzielając je OFS.

Komentarze

  • Wow !!! To jest świetne i dużo się uczę. Naprawdę doceniam poświęcony czas i pouczający opis 🙂 Najlepsze!

Odpowiedź

Można to zrobić w jeden sposób:

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

Komentarze

  • @ Sato Katsura, Tnx dużo działa doskonale. Czy mogę prosić o wyjaśnienie naszym skryptom, aby to zrozumieć! Jestem nowy w Awk. Potrzeba tylko wyjaśnienia dla tej części skryptu: {NF–; for (i = NF-2; i < = NF; i ++) $ i = sprintf ("% 07.2f ", $ i)} 1 '

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *