Jak korzystać z sortowania w poleceniu drukowania awk?


8

Mam kilka poleceń w skrypcie awk, które piszę:

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

Które wyjścia:

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

Jak mogę użyć sortpolecenia w skrypcie awk, aby posortować TYLKO graczy i ich liczby?


3
Biorąc pod uwagę twoje komentarze do odpowiedzi, wydaje się, że wprowadzasz w błąd w swoim skrypcie awk i shell . Wygląda na to, że chcesz dokonać sortowania w skrypcie awk , a nie w wywoływanym skrypcie powłoki . Jeśli to prawda, edytuj swoje pytanie i zamień dwa wystąpienia „shell” na „awk”. Oddzielna uwaga: tak, awk ma funkcję sortowania, ale jest dość zaangażowana: musisz przechowywać wszystkie wiersze w tablicy, wpisując je w drugim polu, z którego musisz wyodrębnić x, a następnie ustawić PROCINFO["sorted_in"]na tajemniczą wartość, następnie wypisz tablicę. Nie poszedłbym tam.
zwets

1
Mam na myśli: nie poszedłbym tam, biorąc pod uwagę prostotę ... | sort -k2,2.
zwets

@zwets Jak zaimplementować, ...| sort -k2,2jeśli istnieją inne wiersze, które należy wydrukować? Sprawdź edytowane pytanie.
KM142646,

Wykonując echolinię nagłówka z powłoki, a następnie uruchom awk | sortpotok.
zwets

Odpowiedzi:


12

możesz dodać | sort -k2do swojego polecenia. To posortuje alfabetycznie na podstawie drugiej kolumny.

Przykład:

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

prowadzi do

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

Niestety używam skryptu, a polecenie sortowania będzie połączone z wieloma innymi wyjściami. Czy istnieje sposób na posortowanie wyniku {print x, $2}bezpośrednio w kodzie skryptu? Podczas instalacji rurowej pojawia się błąd if(sum[x] > 500) {print x, $2} | sort -k2.
KM142646,

3
@KMoy: if(sum[x] > 500) {print x, $2}jest kodem Awk, podczas gdy | sort -k2jest poleceniem powłoki. Oczywiście nie można mieszać tych dwóch, ponieważ są to różne języki. Zamiast tego należy zastosować sortpolecenie do danych wyjściowych interpretera Awk, który uruchamia fragment kodu Awk. Jeśli nie wiesz, co mam na myśli, rozwiń swoje pytanie, aby dać nam pełny obraz.
David Foerster,

1
Piszesz skrypt powłoki, prawda? Masz dwie opcje: 1. Uruchom ./my-script.sh | sort -k2. 2. dodaj `| posortuj -k2` do wiersza skryptu, który generuje wynik podany w pytaniu.
Wayne_Yux

@Wayne_Yux Sprawdź zmiany wprowadzone w oryginalnym pytaniu.
KM142646,

Prawdopodobnie potrzebujesz odpowiedzi od @steeldriver
Wayne_Yux

9

Chociaż nie poleciłbym tego (biorąc pod uwagę względną prostotę przesyłania wyników za pomocą zewnętrznego sortpolecenia), możesz to zrobić przynajmniej w najnowszych wersjach GNU awk (co najmniej 4.0 IIRC), jak opisano w Sortowanie wartości i indeksów tablicy za pomocą gawk

Oto jak możesz to zaimplementować, zakładając, że masz dane w tablicy asocjacyjnej, w której znajduje się indeks Firstname Lastname. Najpierw musisz zdefiniować niestandardową funkcję porównania, która dzieli indeks, porównuje najpierw Lastname(jako remis) Firstnamenp.

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

Teraz możesz użyć PROCINFO["sorted_in"]metody sortowania tablic, o której mowa w komentarzach @zwets

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

Składając to razem

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

Testowanie:

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

W mniejszych lub starszych wersjach awk najlepszym rozwiązaniem może być przechowywanie zaindeksowanych danych Lastname Firstname, sortowanie za pomocą konwencjonalnej asorti, a następnie dzielenie i zamiana pól indeksów podczas przechodzenia przez tablicę, aby ją wydrukować:

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

Aby sortużyć tylko drugiego pola oddzielonego spacjami, użyj klucza -k2,2:

... | sort -k2,2

domyślnie sortsortowanie odbywa się leksykograficznie.

Zauważ, że jeśli nie podasz ostatniego pola dla klucza sortowania, tzn. Jeśli po prostu użyjesz, -k2możesz nie uzyskać pożądanego wyniku, ponieważ będzie to sortzgodne ze wszystkimi polami zaczynającymi się od drugiego.

Sprawdź również man sort.


Proszę sprawdzić komentarz do postu Wayne'a, czego potrzebuję
KM142646

1

Próbować

awk -f myscript.awk | sort -k2

Gdzie myscript.awk zawiera wyłącznie polecenia awk.

Jeśli twój skrypt jest skryptem powłoki, masz kilka opcji, w tym

  • Przepływaj przez sortowanie. ./myscript.bash | sort -k2
  • Przepisz kod jako funkcję w skrypcie
    Zamiast

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

    Zrobić

    $ 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
    

Pamiętaj jednak, że możesz także zastosować sortowanie do struktury do ... done zamiast tworzyć funkcję.

    do
       echo $i
    done | sort

Po co definiować funkcję?
zwets

@zwets, ułatwia przesyłanie wyników dowolnego kodu, w tym pętli struktur kontrolnych, przez potok. Są przypadki, w których jest to niepotrzebne, ale uważam, że jest to użyteczny ogólny wzorzec. Zmodyfikuję moją odpowiedź, aby to zademonstrować.
RedGrittyBrick

1

Aby posortować dane do wydrukowania:

  • Załóżmy, że chcesz wydrukować drugie pole (oddzielone spacjami):

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

    na przykład:

    $cat>data.txt
    1 Kedar 20
    2 Amit 30
    3 Rahul 21
    ^C
    
    $awk '{print $2}' | sort
    Amit
    Kedar
    Rahul
    
  • Jeśli chcesz wydrukować całość, data.txtale posortowane według kolumny 2, to:

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

Użyj tej logiki w swoich wymaganiach.

Możesz użyć man sortdo ciekawszych funkcji sort.


0

co poniżej:

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

działa, kiedy testowałem.


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

Aby posortować dane wyjściowe do pliku:

print "Here are some players and their numbers, sorted by last name"
if(sum[x] > 500) {print x, $2 | "sort -k2,2 > sortedFile"}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.