Cum pot sorta într-un script awk pe Linux?

Am un fișier fruit care are următorul conținut:

Apples, 12 Pears, 50 Cheries, 7 Strawberries, 36 Oranges, 2 

Aș dori să sortez datele numerice ale fișierului:

for(i=1;i<=NF;i++)j+=$i;printf "Fruit %d%s, %d\n",NR,OFS,$1,j | sort -k 2 > "numbers"; j=0" 

Pentru a rula scriptul awk execut comanda :

awk -f numbers fruit 

Fișierul numerelor are același conținut ca fructul, dar primul și al doilea câmp al acestuia sunt copiate în fișierul numerelor.

Comentarii

  • De ce trebuie să sortați în awk? Awk nu ‘ nu are capacități de sortare native, de ce nu ‘ pur și simplu sortați ieșirea?
  • @ terdon GNU awk (care cred că este awk-ul implicit pe Linux) are capacități de sortare native.
  • @EdMorton vezi ultima lor întrebare pentru un anumit context. Și ‘ ai destulă dreptate! GNU awk are asort. Aș fi putut jura că nu ‘ t, dintr-un anumit motiv. Mulțumiri! Nu sunt sigur dacă ar merita, deoarece ‘ ar trebui să citiți întregul fișier într-un tablou și apoi să sortați tabloul, astfel încât sortarea rezultatului ar fi probabil mai eficientă, dar ‘ este mai mult decât suficient pentru aceasta.
  • @terdon Nu are ‘ doar asort() are, de asemenea, mult mai util sorted_in, pentru a vă permite să definiți pur și simplu o comandă pentru for (i in array) vizitați elementele matricei – consultați gnu.org/software/gawk/manual/gawk.html#Controlling-Scanning.I sunt de acord că doar canalizarea către sortarea UNIX ar fi mai eficient pentru această problemă.
  • @EdMorton GNU awk NU este implicit în debian și deopotrivă. ” mawk ” este valoarea implicită, care nu are ‘ nu are ” asort ” funcție încorporată.

Răspuns

GNU awk vă oferă o modalitate îngrijită de a controla modul în care traversați o matrice: consultați Controlling Array Traversal și Controlarea scanării

gawk -F", " " {fruit[$1] = $2} END { OFS = FS printf "\nordered by fruit name\n" PROCINFO["sorted_in"] = "@ind_str_asc" for (f in fruit) print f, fruit[f] printf "\nordered by number\n" PROCINFO["sorted_in"] = "@val_num_desc" for (f in fruit) print f, fruit[f] } " fruit 

ieșiri

ordered by fruit name Apples, 12 Cheries, 7 Oranges, 2 Pears, 50 Strawberries, 36 ordered by number Pears, 50 Strawberries, 36 Apples, 12 Cheries, 7 Oranges, 2 

Răspuns

Puteți trece de fapt awk „s print prin "sort" (notați ghilimelele):

$ awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn"}" fruit Fruit 2 Pears, 50 Fruit 4 Strawberries, 36 Fruit 1 Apples, 12 Fruit 3 Cheries, 7 Fruit 5 Oranges, 2 

Deci, pentru a scrie către numbers, puteți face:

awk "{print "Fruit",NR, $0 | "sort -k 2 -t, -rn > numbers"}" fruit 

Rețineți că v-am simplificat puțin awk-ul. Nu este nevoie să folosiți printf aici sau să imprimați explicit OFS deoarece nu îl schimbați oriunde. deci nu vedeți ce face for(i=1;i<=NF;i++)j+=$i. Aveți deja numărul cu NR și printf nu ați folosit oricum j.

Comentarii

  • În loc să apelați sort în interiorul awk, ‘ este mai simplu și mai eficient pentru a imprima simplu în awk și pipe ieșirea awk pentru a sorta: awk '{print ...}' fruit | sort ....
  • @EdMorton oh, absolut! Nu aș folosi niciodată această abordare, ceea ce ‘ este punctul? Dar acesta este ceea ce a solicitat OP .
  • Deseori găsesc o cerință de sortare în gawk, când nu ‘ nu vreau să sortez întreaga ieșire. De exemplu, colectarea și raportarea statisticilor separat pentru fiecare fișier de intrare. Pot folosi o metodă de decorare / sortare / clip pentru realizează chei simple din date complexe (de exemplu, clasificați supraîncărcările echipamentelor electrice folosind o serie laterală de evaluări maxime). De asemenea, sortarea externă folosește fișiere de lucru pe disc și o strategie de divizare / îmbinare. sortarea poate folosi metode mai bune.
  • @JoeSkora nu aveți nevoie ‘ de care trebuie să generați un subshell din awk și apoi să sperați că tamponarea tuturor celor implicați duce la ieșire de la subshell ajungând la stdout după restul ieșirii din comanda awk în loc de înainte sau, dacă este cazul, în mijlocul acesteia. Doar faceți awk '{print (NR>1), $0}' | sort -k1,1n -k2 | cut -d' ' -f2-
  • @EdMorton Îmi place să tipăresc ideea condițională, grozavă. Ultima parte poate fi simplificată în continuare, lăsând acest lucru. awk '{print (NR>1),$0}' | sort ... | cut -c3-.

Răspuns

Probabil că am avut o problemă serioasă problemă cu SunOS nawk în 2002. Am găsit scriptul meu de test care conținea trei implementări awk care rulează în non-GNU awk:

(a) eSort: folosește un fișier de lucru și citește înapoi printr-o comandă de sortare care rulează. Nu este bine în cazul meu, deoarece făceam lucruri prin ssh pentru monitorizarea fără agenți, iar fișierele de lucru externe erau prea invazive pentru serverele noastre live.

(b) qSort: un tip de partiție recursivă. Performanță slabă pentru date mari și rupe stiva în mawk pentru> 2000 de elemente. Amuzant de scris totuși.

(c) hSort: un algoritm sort-in-situ în 15 linii. Acest heap folosește un algoritm de indexare pentru a susține un arbore binar (vezi Wikipedia).

Acest script bash conține funcții awk hSort și hUp care implementează sortarea reală. O linie de acțiune pune toate intrările într-o matrice, iar blocul END apelează hSort și raportează rezultatele.

Datele de intrare sunt conținutul „man bash”, o dată ca linii și din nou ca cuvinte. Folosim wc pentru a dovedi că nu s-a pierdut nimic și sortăm -c pentru a demonstra că ieșirea este sortată. Timpurile includ citirea și tipărirea capetelor.

Aceasta este imaginea de testare:

Paul--) ./hSort Sorted 5251 elements. real 0m0.120s user 0m0.116s sys 0m0.004s 5251 44463 273728 hSort.raw sort: hSort.raw:2: disorder: 5251 44463 273728 hSort.srt Sorted 44463 elements. real 0m1.336s user 0m1.316s sys 0m0.008s 44463 44463 265333 hSort.raw sort: hSort.raw:3: disorder: Commands 44463 44463 265333 hSort.srt 

Acesta este scriptul. Bucurați-vă!

#! /bin/bash export LC_ALL="C" #### Heapsort algorithm. function hSort { #:: (void) < text local AWK=""" #.. Construct the heap, then unfold it. function hSort (A, Local, n, j, e) { for (j in A) ++n; for (j = int (n / 2); j > 0; --j) hUp( j, A[j], n, A); for (j = n; j > 1; --j) { e = A[j]; A[j] = A[1]; hUp( 1, e, j - 1, A); } return (0 + n); } #.. Given an empty slot and its contents, pull any bigger elements up the tree. function hUp (j, e, n, V, Local, k) { while ((k = j + j) <= n) { if (k + 1 <= n && STX V[k] < STX V[k + 1]) ++k; if (STX e >= STX V[k]) break; V[j] = V[k]; j = k; } V[j] = e; } { U[++nU] = $0; } END { sz = hSort( U); printf ("\nSorted %s elements.\n", sz) | "cat 1>&2"; for (k = 1; k in U; ++k) print U[k]; } """ mawk -f <( printf "%s\n" "${AWK}" ) } #### Test Package Starts Here. function Test { time hSort < hSort.raw > hSort.srt for fn in hSort.{raw,srt}; do wc "${fn}"; LC_ALL="C" sort -c "${fn}"; done } AWK_LINE="{ sub (/^[ \011]+/, ""); print; }" AWK_WORD="{ for (f = 1; f <= NF; ++f) print $(f); }" #xxx : > hSort.raw; Test #.. Edge cases. #xxx echo "Hello" > hSort.raw; Test #xxx { echo "World"; echo "Hello"; } > hSort.raw; Test man bash | col -b | mawk "${AWK_LINE}" > hSort.raw; Test man bash | col -b | mawk "${AWK_WORD}" > hSort.raw; Test 

Răspuns

HeapSort poate fi scris în awk standard în mai puțin mai mult de 20 de linii. Nu orbitor de rapid, dar se potrivește destul de bine cu limba.

Comentarii

  • Oh, nu am ‘ nu-l postați. I-am afirmat existența și l-am lăsat ca exercițiu pentru cititor.
  • Am postat codul și testul pe 9 ianuarie 2020

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *