Come usare l'ordinamento su un comando di stampa awk?


8

Ho un paio di comandi in uno script awk che sto scrivendo:

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

Quali uscite:

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

Come posso usare il sortcomando nel mio script awk per ordinare SOLO i giocatori e i loro numeri?


3
Dati i tuoi commenti sulle risposte, sembra che tu abbia confuso lo script di awk e shell nella tua domanda. Sembra che tu voglia fare l'ordinamento all'interno del tuo script awk , non nello script shell che lo invoca. Se è corretto, modifica la domanda e sostituisci le due occorrenze di "shell" con "awk". In una nota a parte: sì, awk ha una funzione di ordinamento, ma è abbastanza coinvolto: devi memorizzare tutte le linee in un array, digitate sul loro secondo campo, da cui dovrai estrarre x, quindi impostare PROCINFO["sorted_in"]su un valore criptico, quindi emettere l'array. Non ci andrei.
zwets

1
Voglio dire: non ci andrei data la semplicità di ... | sort -k2,2.
zwets

@zwets Come implementare ...| sort -k2,2se ci sono altre linee che devono essere stampate? Controlla la domanda modificata.
KM142646,

Inserendo echola riga di intestazione dalla shell, quindi eseguire la awk | sortpipeline.
zwets

Risposte:


12

puoi aggiungere | sort -k2al tuo comando. Questo ordinerà alfabeticamente in base alla seconda colonna.

Esempio:

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

risultati in

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

Sfortunatamente sto usando uno script, e il comando sort sarà combinato con molti altri output. C'è un modo per ordinare l'output di {print x, $2}direttamente nel codice dello script? Ricevo un errore durante il piping if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646,

3
@KMoy: if(sum[x] > 500) {print x, $2}è il codice Awk mentre | sort -k2è un comando shell. Ovviamente non puoi mescolare i due in quel modo perché sono lingue diverse. È invece necessario applicare il sortcomando all'output dell'interprete Awk che esegue lo snippet di codice Awk. Se non sai cosa intendo, espandi la tua domanda per darci il quadro completo.
David Foerster,

1
Stai scrivendo uno script di shell, giusto? Quindi hai due opzioni: 1. esegui ./my-script.sh | sort -k2. 2. aggiungi `| ordina -k2` sulla riga del tuo script che produce l'output indicato nella tua domanda.
Wayne_Yux,

@Wayne_Yux Controlla le modifiche apportate alla domanda originale.
KM142646,

Quindi probabilmente avrai bisogno della risposta di @steeldriver
Wayne_Yux il

9

Anche se non lo consiglierei (data la relativa semplicità di sorteseguire il piping del risultato tramite un comando esterno ), puoi farlo almeno con le versioni recenti di GNU awk (almeno 4.0 IIRC), come descritto in Ordinamento di valori di array e indici con gawk

Ecco come potresti implementarlo, supponendo che tu abbia i dati in un array associativo in cui si trova l'indice Firstname Lastname. Per prima cosa devi definire una funzione di confronto personalizzata che divide l'indice, poi confronta prima Lastname(come un pareggio) ad Firstnamees.

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;
}

Ora puoi usare il PROCINFO["sorted_in"]metodo di ordinamento degli array menzionato nei commenti di @zwets

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

Mettendolo insieme

#!/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];
}

test:

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

Nelle versioni precedenti o precedenti di awk, la soluzione migliore potrebbe essere quella di archiviare i dati indicizzati Lastname Firstnameinvece, ordinare con il convenzionale asorti, quindi dividere e scambiare i campi degli indici mentre si attraversa l'array per stamparlo:

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

Per utilizzare sortsolo il secondo campo separato da spazi bianchi, utilizzare il tasto -k2,2:

... | sort -k2,2

per impostazione predefinita sortfa l'ordinamento lessicografico.

Si noti che, se non si menziona l'ultimo campo per la chiave di ordinamento, ad esempio se si utilizza semplicemente, -k2è possibile che non si ottenga il risultato desiderato, poiché ciò sortcorrisponderà a tutti i campi a partire dal secondo.

Controlla anche man sort.


Per favore, controlla i commenti sul post di Wayne per quello che mi serve
KM142646,

1

Provare

awk -f myscript.awk | sort -k2

Dove myscript.awk contiene comandi puramente awk.

Se il tuo script reale è uno script di shell, hai diverse opzioni tra cui

  • Uscita del tubo attraverso l'ordinamento. ./myscript.bash | sort -k2
  • Riscrivi il codice come funzione all'interno dello script
    anziché

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

    Fare

    $ 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
    

Ma nota che puoi anche applicare l'ordinamento alla struttura do ... done invece di creare una funzione.

    do
       echo $i
    done | sort

Perché definire la funzione?
zwets

@zwets, rende più semplice alimentare i risultati di codice arbitrario, comprese le strutture di controllo in loop, attraverso una pipeline. Ci sono casi in cui non è necessario ma lo trovo un utile schema generale. Modificherò la mia risposta per dimostrarlo.
RedGrittyBrick

1

Per ordinare i dati da stampare:

  • Supponiamo di voler stampare il 2 ° campo (spazi separati) utilizzare questo:

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

    per esempio:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Se vuoi stampare tutto il tuo data.txtma ordinato sulla colonna 2, quindi:

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

Usa questa logica (s) nel tuo requisito.

È possibile utilizzare man sortper le funzionalità più interessanti di sort.


0

che dire di seguito:

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

funziona quando ho provato.


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

Per ordinare l'output in un file:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.