Wie kann ich unter Linux in einem awk-Skript sortieren?

Ich habe eine Datei fruit mit folgendem Inhalt:

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

Ich möchte die numerischen Daten der Datei sortieren:

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

Um das awk-Skript auszuführen, führe ich den Befehl aus :

awk -f numbers fruit 

Die Zahlendatei hat den gleichen Inhalt wie Obst, aber das 1. und 2. Feld werden in die Zahlendatei kopiert.

Kommentare

  • Warum müssen Sie in awk sortieren? Awk ‚ verfügt nicht über native Sortierfunktionen. Warum ‚ sortieren Sie stattdessen nicht einfach die Ausgabe?
  • @ terdon GNU awk (von dem ich denke, dass es unter Linux das Standard-awk ist) verfügt über native Sortierfunktionen.
  • @EdMorton siehe ihre letzte Frage für irgendein Kontext. Und Sie ‚ haben ganz recht! GNU awk hat asort. Ich hätte schwören können, dass es aus irgendeinem Grund nicht ‚ t war. Vielen Dank! Ich bin mir nicht ganz sicher, ob es sich lohnt, da Sie ‚ die gesamte Datei in ein Array lesen und dann das Array sortieren müssen, sodass das Sortieren der Ausgabe wahrscheinlich immer noch effizienter ist. Aber ‚ ist mehr als genug dafür.
  • @terdon ‚ hat nicht nur asort() Es hat auch das weitaus nützlichere sorted_in, mit dem Sie einfach eine Reihenfolge für for (i in array) definieren können Besuchen Sie die Array-Elemente – siehe gnu.org/software/gawk/manual/gawk.html#Controlling-Scanning.I Ich bin damit einverstanden, dass nur eine UNIX-Sortierung durchgeführt wird Effizienter für dieses Problem.
  • @EdMorton GNU awk ist NICHT die Standardeinstellung in Debian und gleichermaßen. “ mawk “ ist die Standardeinstellung, die ‚ keine “ asort “ integrierte Funktion.

Antwort

Mit GNU awk können Sie auf übersichtliche Weise steuern, wie Sie ein Array durchlaufen: siehe Steuern der Array-Durchquerung und Steuern des Scannens

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 

gibt

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 

aus

Antwort

Sie können awks „print durch "sort" (beachten Sie die Anführungszeichen):

$ 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 

Um also in numbers zu schreiben, können Sie Folgendes tun:

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

Beachten Sie, dass ich Ihre awk ein wenig vereinfacht habe. Es ist nicht erforderlich, printf hier zu verwenden oder explizit zu drucken OFS, da Sie es nirgendwo ändern. I al Sehen Sie also nicht, was Ihre for(i=1;i<=NF;i++)j+=$i tut. Sie haben bereits die Nummer mit NR und Ihre printf hat j ohnehin nicht verwendet.

Kommentare

  • Anstatt sort in awk aufzurufen, ist es ‚ einfacher und effizienter, einfach zu drucken in awk und Pipe die awk-Ausgabe zum Sortieren: awk '{print ...}' fruit | sort ....
  • @EdMorton oh, absolut! Ich würde diesen Ansatz niemals selbst verwenden, was ‚ ist der Punkt? Aber das hat das OP verlangt .
  • Ich finde oft eine Anforderung zum Sortieren Wenn ich in gawk nicht ‚ die gesamte Ausgabe sortieren möchte, kann ich beispielsweise Statistiken für jede Eingabedatei separat erfassen und melden. Ich kann eine Dekorations- / Sortier- / Clip-Methode verwenden, um Erstellen Sie einfache Schlüssel aus komplexen Daten (z. B. Rangüberlastungen elektrischer Geräte mithilfe eines seitlichen Arrays mit maximalen Bewertungen). Bei der externen Sortierung werden Datenträger-Arbeitsdateien und eine Split / Merge-Strategie verwendet. Intern sort kann bessere Methoden verwenden.
  • @JoeSkora Sie ‚ müssen keine Subshell von awk erzeugen und hoffen dann, dass die Pufferung von allen Beteiligten zur Ausgabe führt von der Subshell, die nach dem Rest der Ausgabe des Befehls awk statt davor oder, falls zutreffend, in der Mitte, auf stdout wechselt. Machen Sie einfach awk '{print (NR>1), $0}' | sort -k1,1n -k2 | cut -d' ' -f2-
  • @EdMorton Ich drucke gerne die bedingte, großartige Idee. Der letzte Teil kann weiter vereinfacht werden. awk '{print (NR>1),$0}' | sort ... | cut -c3-.

Antwort

Ich muss eine ernsthafte gehabt haben Problem mit SunOS nawk im Jahr 2002. Ich habe mein Testskript gefunden, das drei awk-Implementierungen enthielt, die in nicht-GNU awk ausgeführt werden:

(a) eSort: Verwendet eine Arbeitsdatei und liest einen Befehl zum Ausführen einer Pipe zurück. In meinem Fall nicht gut, weil ich für die agentenlose Überwachung Dinge über ssh erledigt habe und externe Arbeitsdateien für unsere Live-Server zu invasiv waren.

(b) qSort: eine rekursive Partitionssortierung. Die Leistung ist schlecht für große Datenmengen und bricht den Stapel in mawk für> 2000 Elemente. Es macht Spaß zu schreiben.

(c) hSort: Ein Sort-in-situ-Algorithmus in 15 Zeilen. Dieser Heap verwendet einen Indexierungsalgorithmus, um einen Binärbaum zu unterstützen (siehe Wikipedia).

Dieses Bash-Skript enthält die awk-Funktionen hSort und hUp, die die eigentliche Sortierung implementieren. Eine Aktionszeile fügt alle Eingaben in ein Array ein, und der END-Block ruft hSort auf und meldet die Ergebnisse.

Die Eingabedaten sind der Inhalt von „man bash“, einmal als Zeilen und erneut als Wörter. Wir verwenden wc, um zu beweisen, dass nichts verloren gegangen ist, und sort -c, um zu beweisen, dass die Ausgabe sortiert ist. Die Timings beinhalten den Lese- und Druckaufwand.

Dies ist die Testaufnahme:

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 

Dies ist das Skript. Viel Spaß!

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

Antwort

HeapSort kann in weniger in Standard-awk geschrieben werden als 20 Zeilen. Nicht blendend schnell, aber es passt ziemlich gut zur Sprache.

Kommentare

  • Oh, ich habe nicht ‚ poste es nicht. Ich habe seine Existenz behauptet und es als Übung für den Leser hinterlassen.
  • Veröffentlichte den Code und den Test am 9. Januar 2020

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.