Wie verwende ich sort für einen awk print-Befehl?


8

Ich habe ein paar Befehle in einem awk-Skript, das ich schreibe:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2}

Welche Ausgänge:

Here are some players and their numbers, sorted by last name
Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55

Wie kann ich den sortBefehl in meinem awk-Skript verwenden , um NUR die Spieler und ihre Nummern zu sortieren?


3
Angesichts Ihrer Kommentare zu den Antworten scheinen Sie awk und Shell- Skript in Ihrer Frage zu verwirren . Es scheint, dass Sie die Sortierung in Ihrem awk-Skript durchführen möchten , nicht in dem Shell- Skript, das es aufruft. Wenn dies korrekt ist, bearbeiten Sie bitte Ihre Frage und ersetzen Sie die beiden Vorkommen von 'shell' durch 'awk'. Ein separater Hinweis: Ja, awk verfügt über eine Sortierfunktion, die jedoch sehr aufwändig ist: Sie müssen alle Zeilen in einem Array speichern, das in ihrem zweiten Feld eingegeben ist, aus dem Sie extrahieren müssen x, und dann PROCINFO["sorted_in"]auf einen kryptischen Wert setzen. Geben Sie dann das Array aus. Ich würde nicht dorthin gehen.
zwets

1
Ich meine: Ich würde angesichts der Einfachheit von nicht dorthin gehen ... | sort -k2,2.
zwets

@zwets Wie würde ich implementieren, ...| sort -k2,2wenn andere Zeilen gedruckt werden müssen? Überprüfen Sie die bearbeitete Frage.
KM142646

Durch echo-ing aus der Schale die Kopfzeile, führt dann die awk | sortPipeline.
zwets

Antworten:


12

Sie können | sort -k2Ihrem Befehl hinzufügen . Dies wird alphabetisch nach der zweiten Spalte sortiert.

Beispiel:

$ echo "Lebron James 23
Kevin Durant 35
Kobe Bryant 24
Blake Griffin 32
Dikembe Mutumbo 55" | sort -k2

führt zu

Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55

Leider verwende ich ein Skript und der Befehl sort wird mit vielen anderen Ausgaben kombiniert. Gibt es eine Möglichkeit, die Ausgabe {print x, $2}direkt im Skriptcode zu sortieren ? Beim Verrohren wird ein Fehler angezeigt if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646

3
@KMoy: if(sum[x] > 500) {print x, $2}ist Awk-Code, während | sort -k2es sich um einen Shell-Befehl handelt. Offensichtlich kann man die beiden nicht so mischen, weil sie verschiedene Sprachen sind. Stattdessen müssen Sie den sortBefehl auf die Ausgabe des Awk-Interpreters anwenden, auf dem Ihr Awk-Code-Snippet ausgeführt wird. Wenn Sie nicht wissen, was ich meine, erweitern Sie bitte Ihre Frage, um uns das vollständige Bild zu geben.
David Foerster

1
Sie schreiben ein Shell-Skript, richtig? Dann haben Sie zwei Möglichkeiten: 1. Ausführen ./my-script.sh | sort -k2. 2. füge `| hinzu sortiere -k2` in die Zeile deines Skripts, die die in deiner Frage angegebene Ausgabe erzeugt.
Wayne_Yux

@Wayne_Yux Bitte überprüfen Sie die Änderungen an der ursprünglichen Frage.
KM142646

Dann brauchen Sie wahrscheinlich die Antwort von @steeldriver
Wayne_Yux

9

Obwohl ich es nicht empfehlen würde (angesichts der relativ einfachen Weiterleitung des Ergebnisses über einen externen sortBefehl), können Sie dies zumindest mit neueren Versionen von GNU awk (mindestens 4.0 IIRC) tun, wie unter Sortieren von Array-Werten und -Indizes mit gawk beschrieben

So können Sie es implementieren, vorausgesetzt, Sie haben die Daten in einem assoziativen Array, in dem sich der Index befindet Firstname Lastname. Zuerst müssen Sie eine benutzerdefinierte Vergleichsfunktion definieren, die den Index aufteilt, zuerst vergleicht und Lastnamedann (als Tie Breaker) Firstnamez

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

Jetzt können Sie die PROCINFO["sorted_in"]in den Kommentaren von @zwets erwähnte Array-Sortiermethode verwenden

PROCINFO["sorted_in"] = "mycmp";
for(i in a) print i, a[i];

Etwas zusammensetzen

#!/usr/bin/gawk -f

function mycmp(ia, va, ib, vb, sa, sb) {
  if(split(toupper(ia), sa) && split(toupper(ib), sb)) {
    if(sa[2] < sb[2]) return -1;
    else if (sa[2] > sb[2]) return 1;
    else {
      # compare first names
      if(sa[1] < sb[1]) return -1;
      else if (sa[1] > sb[1]) return 1;
      else return 0;
    }
  }
  else return 0;
}

{
  a[$1" "$2] = $3;
}

END {
  PROCINFO["sorted_in"] = "mycmp";
  for(i in a) print i, a[i];
}

Testen:

$ ./namesort.awk yourfile
Kobe Bryant 24
Kevin Durant 35
Blake Griffin 32
Lebron James 23
Dikembe Mutumbo 55

In kleineren oder älteren Versionen von awk ist es möglicherweise am besten, die von indizierten Daten zu speichern, Lastname Firstnamestattdessen mit den herkömmlichen zu sortieren asortiund dann die Felder der Indizes zu teilen und auszutauschen, während Sie das Array durchlaufen, um es zu drucken:

awk '
  {a[$2" "$1]=$3} 
  END {
    n=asorti(a,b); for (i=1;i<=n;i++) {split(b[i],s); print s[2], s[1], a[b[i]]}
}' yourfile

5

Um sortnur durch das Leerzeichen getrennt zweite Feld Taste -k2,2:

... | sort -k2,2

Standardmäßig sorterfolgt die Sortierung lexikografisch.

Beachten Sie, dass -k2Sie möglicherweise nicht das gewünschte Ergebnis erhalten , wenn Sie das letzte Feld für den Sortierschlüssel nicht erwähnen, dh wenn Sie nur das Feld verwenden, da dies sortfür alle Felder ab der zweiten gilt.

Überprüfen Sie auch man sort.


Bitte überprüfen Sie den Kommentar zu Waynes Beitrag auf das, was ich brauche
KM142646

1

Versuchen

awk -f myscript.awk | sort -k2

Wobei myscript.awk rein awk-Befehle enthält.

Wenn Ihr eigentliches Skript ein Shell-Skript ist, haben Sie mehrere Möglichkeiten, einschließlich

  • Rohrausgabe durch Sortierung. ./myscript.bash | sort -k2
  • Rewrite - Code als Funktion im Skript
    statt

    $ cat t1
    #!/bin/bash
    for i in 2 4 3 1 5;
    do
      echo $i
    done
    
    $ ./t1
    2
    4
    3
    1
    5
    

    Tun

    $ cat t2
    #!/bin/bash
    function foo {
      for i in 2 4 3 1 5;
      do
        echo $i
      done
    }
    foo | sort
    
    $ ./t2
    1
    2
    3
    4
    5
    

Beachten Sie jedoch, dass Sie die Sortierung auch auf die do ... done-Struktur anwenden können, anstatt eine Funktion zu erstellen.

    do
       echo $i
    done | sort

Warum die Funktion definieren?
zwets

@zwets erleichtert es, die Ergebnisse von beliebigem Code, einschließlich Schleifensteuerungsstrukturen, über eine Pipeline zu übertragen. Es gibt Fälle, in denen es unnötig ist, aber ich finde es ein nützliches allgemeines Muster. Ich werde meine Antwort bearbeiten, um dies zu demonstrieren.
RedGrittyBrick

1

So sortieren Sie Ihre zu druckenden Daten:

  • Angenommen, Sie möchten das zweite Feld (durch Leerzeichen getrennt) drucken. Verwenden Sie Folgendes:

    awk '{print $2}' data.txt | sort
    

    z.B:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Wenn Sie das gesamte drucken möchten, data.txtaber in Spalte 2 sortiert sind, dann:

    $awk '{print}'|sort -k2
    2 Amit 30
    1 Kedar 20
    3 Rahul 21
    

Verwenden Sie diese Logik (en) in Ihrer Anforderung.

Sie können man sortfür interessantere Funktionen von verwenden sort.


0

Was ist mit unten:

 awk 'BEGIN{str="1\n2\n3\n4"; system("echo -e \""str"\" | sort -r")}'

es funktioniert, wenn ich getestet habe.


0
print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2"}

So sortieren Sie die Ausgabe in eine Datei:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.