Jak mogę posortować zawartość skryptu awk w systemie Linux?

Mam plik fruit, który ma następującą zawartość:

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

Chciałbym posortować numeryczne dane pliku:

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

W celu uruchomienia skryptu awk uruchamiam polecenie :

awk -f numbers fruit 

Plik liczb ma taką samą zawartość jak owoc, ale jego pierwsze i drugie pole są kopiowane do pliku liczb.

Komentarze

  • Dlaczego musisz sortować w awk? Awk nie ' nie ma natywnych możliwości sortowania, dlaczego nie ' czy zamiast tego po prostu sortujesz dane wyjściowe?
  • @ terdon GNU awk (który myślę, że jest domyślnym awk w Linuksie) ma natywne możliwości sortowania.
  • @EdMorton Zobacz ich ostatnie pytanie jakiś kontekst. I masz ' masz rację! GNU awk ma asort. Mógłbym przysiąc, że z jakiegoś powodu nie ' t. Dzięki! Nie jestem do końca pewien, czy to się opłaca, ponieważ ' d musisz wczytać cały plik do tablicy, a następnie posortować tablicę, więc sortowanie danych wyjściowych będzie prawdopodobnie bardziej wydajne, ale to ' jest do tego więcej niż wystarczające.
  • @terdon Nie ' nie ma po prostu asort() ma również znacznie bardziej przydatne sorted_in, pozwalające po prostu zdefiniować kolejność for (i in array) odwiedź elementy tablicy – zobacz gnu.org/software/gawk/manual/gawk.html#Controlling-Scanning.I zgadzam się, że zwykłe przesłanie do sortowania w systemie UNIX byłoby bardziej efektywny w przypadku tego problemu.
  • @EdMorton GNU awk NIE JEST domyślny w debianie i podobnych. ” mawk ” jest ustawieniem domyślnym, które nie ' nie ma ” asort „.

Odpowiedź

GNU awk zapewnia zgrabny sposób kontrolowania przechodzenia przez tablicę: patrz Kontrolowanie przemierzania tablicy i Kontrolowanie skanowania

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 

wyjścia

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 

Odpowiedź

W rzeczywistości możesz przekazać awk „s print do "sort" (zwróć uwagę na cudzysłowy):

$ 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 

Aby napisać do numbers, możesz:

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

Zwróć uwagę, że nieco uprościłem Twój awk. Nie ma potrzeby używania printf tutaj ani jawnego drukowania OFS, ponieważ nigdzie go nie zmieniasz. więc nie sprawdzaj, co robi Twój for(i=1;i<=NF;i++)j+=$i. Masz już numer z NR, a Twój printf i tak nie był „t użyty j.

Komentarze

  • Zamiast wywoływać sort wewnątrz awk, ' prostsze i wydajniejsze jest drukowanie w awk i potokiem wyjście awk do sortowania: awk '{print ...}' fruit | sort ....
  • @EdMorton och, absolutnie! Nigdy nie użyłbym tego podejścia sam, co ' o co chodzi? Ale o to prosił OP .
  • Często muszę sortować w gawk, kiedy ' nie chcę sortować całego wyniku. Na przykład, zbierając i raportując statystyki osobno dla każdego pliku wejściowego. Mogę użyć metody dekorowania / sortowania / przycinania, tworzenie prostych kluczy na podstawie złożonych danych (np. ocenianie przeciążeń sprzętu elektrycznego za pomocą bocznej tablicy maksymalnych wartości znamionowych). Ponadto sortowanie zewnętrzne wykorzystuje dyskowe pliki robocze oraz strategię podziału / łączenia. sort może używać lepszych metod.
  • @JoeSkora nie ' nie musisz tworzyć podpowłoki z awk, a następnie mieć nadzieję, że buforowanie wszystkich zainteresowanych prowadzi do wyjścia z podpowłoki przechodzącej do stdout po reszcie wyjścia polecenia awk zamiast przed nim lub, jeśli ma to zastosowanie, w środku. Po prostu zrób awk '{print (NR>1), $0}' | sort -k1,1n -k2 | cut -d' ' -f2-
  • @EdMorton Lubię drukować warunkowy, świetny pomysł. Ostatnią część można jeszcze bardziej uprościć, pozostawiając to. awk '{print (NR>1),$0}' | sort ... | cut -c3-.

Odpowiedź

Musiałem mieć poważną problem z SunOS nawk w 2002. Znalazłem mój skrypt testowy, który zawierał trzy implementacje awk działające w awk innym niż GNU:

(a) eSort: używa pliku roboczego i odczytuje z powrotem przez potokowe polecenie sortowania. Nie dobrze w moim przypadku, ponieważ robiłem rzeczy przez ssh w celu monitorowania bez agentów, a zewnętrzne pliki robocze były zbyt inwazyjne dla naszych serwerów live.

(b) qSort: rekurencyjne sortowanie partycji. Zła wydajność dla dużych danych i zrywa stos w mawk dla> 2000 elementów. Ale fajnie się pisze.

(c) hSort: algorytm sortowania na miejscu w 15 wierszach. Ta sterta używa algorytmu indeksującego do obsługi drzewa binarnego (patrz Wikipedia).

Ten skrypt basha zawiera funkcje awk hSort i hUp, które implementują faktyczne sortowanie. Jedna linia akcji umieszcza wszystkie dane wejściowe w tablicy, a blok END wywołuje hSort i podaje wyniki.

Dane wejściowe to zawartość „man bash”, raz jako wiersze, a ponownie jako słowa. Używamy wc, aby udowodnić, że nic nie zginęło, i posortuj -c, aby udowodnić, że wyjście jest posortowane. Czasy obejmują czas odczytu i drukowania.

To jest zdjęcie testowe:

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 

To jest skrypt. Ciesz się!

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

Odpowiedź

HeapSort można zapisać w standardowym awk w mniej niż 20 linii. Niezbyt szybko, ale dość dobrze pasuje do języka.

Komentarze

  • Och, nie ' t opublikować. Potwierdziłem jego istnienie i zostawiłem go jako ćwiczenie dla czytelnika.
  • Opublikowałem kod i przetestowałem go 9 stycznia 2020 r.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *