Hvordan kan jeg sortere i et awk-skript på Linux?

Jeg har fil fruit som har følgende innhold:

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

Jeg vil sortere de numeriske dataene i filen:

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

For å kjøre awk-skriptet kjører jeg kommandoen :

awk -f numbers fruit 

Tallfilen har samme innhold som frukt, men første og andre felt kopieres til tallfilen.

Kommentarer

  • Hvorfor trenger du å sortere i awk? Awk har ikke ‘ t native sorteringsfunksjoner, hvorfor ikke ‘ t du bare sorterer utdata i stedet?
  • @ terdon GNU awk (som jeg TROR er standard awk på Linux) har innfødte sorteringsfunksjoner.
  • @EdMorton se deres siste spørsmål for noe sammenheng. Og du ‘ har helt rett! GNU awk har asort. Jeg kunne ha sverget at det ikke ‘ t, av en eller annen grunn. Takk! Ikke helt sikker på om det ville være verdt det siden du ‘ måtte lese hele filen i en matrise og deretter sortere matrisen, så sortering av utdata vil sannsynligvis fremdeles være mer effektiv, men det ‘ er mer enn nok til dette.
  • @terdon Det har ikke ‘ t har bare asort() det har også den langt mer nyttige sorted_in, slik at du bare kan definere en ordre for for (i in array) besøk matriseelementene – se gnu.org/software/gawk/manual/gawk.html#Controlling-Scanning.I er enig i at bare rørledning til UNIX-sortering ville være mer effektivt for dette problemet skjønt.
  • @EdMorton GNU awk er IKKE standard i debian og likt. » mawk » er standard, som ikke har ‘ t » asort » innebygd funksjon.

Svar

GNU awk gir deg en fin måte å kontrollere hvordan du krysser over en matrise: se Kontrollere Array Traversal og Kontrollere skanning

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 

utganger

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 

Svar

Du kan faktisk sende awk «s print til "sort" (merk anførselstegnene):

$ 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 

Så, for å skrive til numbers, kan du gjøre:

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

Merk at jeg forenklet din awk litt. Det er ikke nødvendig å bruke printf her eller å eksplisitt skrive ut OFS siden du ikke endrer det noe sted. Jeg al så ikke se hva for(i=1;i<=NF;i++)j+=$i gjør. Du har allerede nummeret med NR og printf brukte uansett ikke j.

Kommentarer

  • I stedet for å ringe sort inni awk er det ‘ enklere og mer effektivt å bare skrive ut i awk og rør awk-utgangen for å sortere: awk '{print ...}' fruit | sort ....
  • @EdMorton oh, absolutt! Jeg ville aldri brukt denne tilnærmingen selv, hva ‘ er poenget? Men dette ba OPen om .
  • Jeg finner ofte et krav om å sortere innen gawk, når jeg ikke ‘ ikke vil sortere hele utdataene. For eksempel, samle inn og rapportere statistikk separat for hver inndatafil. Jeg kan bruke en dekorere / sortere / klipp-metode for å skreddersy enkle nøkler fra komplekse data (f.eks. rangere overbelastning av elektrisk utstyr ved hjelp av et sidearrangement med maks rangeringer). Ekstern sortering bruker også diskarbeidsfiler og en splitt / flettingsstrategi sortering kan bruke bedre metoder.
  • @JoeSkora du trenger ikke ‘ t trenger å gyte en subshell fra awk og håper deretter at buffringen fra alle berørte fører til utdata fra subshell kommer til stdout etter resten av utdata fra awk-kommandoen i stedet for før den eller, hvis aktuelt, i midten av den. Bare gjør awk '{print (NR>1), $0}' | sort -k1,1n -k2 | cut -d' ' -f2-
  • @EdMorton Jeg liker å skrive ut den betingede, gode ideen. Den siste delen kan forenkles ved å forlate dette. awk '{print (NR>1),$0}' | sort ... | cut -c3-.

Svar

Jeg må ha hatt en alvorlig problem med SunOS nawk i 2002. Jeg fant testskriptet mitt som inneholdt tre awk-implementeringer som kjører i ikke-GNU awk:

(a) eSort: bruker en arbeidsfil og leser tilbake gjennom en pipeløpssorteringskommando. Ikke bra i mitt tilfelle, fordi jeg gjorde ting gjennom ssh for agentløs overvåking, og eksterne arbeidsfiler var for invasive for våre live servere.

(b) qSort: en rekursiv partisjonssort. Ytelsen er dårlig for store data, og bryter stabelen i mawk for> 2000 elementer. Moro å skrive skjønt.

(c) hSort: en sorterings-in-situ algoritme i 15 linjer. Denne haugen bruker en indekseringsalgoritme for å støtte et binært tre (se Wikipedia).

Dette bash-skriptet inneholder awk-funksjoner hSort og hUp som implementerer den faktiske sorteringen. Én handlingslinje plasserer alle inngangene i en matrise, og END-blokken kaller hSort og rapporterer resultatene.

Inndataene er innholdet i «man bash», en gang som linjer, og igjen som ord. Vi bruker wc for å bevise at ingenting gikk tapt, og sorter -c for å bevise at utdataene er sortert. Tidsplanene inkluderer lese- og utskriftsoverhead.

Dette er testbildet:

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 

Dette er skriptet. Kos deg!

#! /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 

Svar

HeapSort kan skrives i standard awk på mindre enn 20 linjer. Ikke raskt, men det passer rimelig bra til språket.

Kommentarer

  • Åh, jeg gjorde ikke ‘ t legg det ut. Jeg hevdet dens eksistens, og la den være som en øvelse for leseren.
  • Lagt ut koden og testen 9. jan 2020

Legg igjen en kommentar

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