Czy zamiast tego można użyć awk?


17

Chciałbym uzyskać numer ratingjako wynik z tego

# nc localhost 9571 
language:
language:en_ZA.UTF-8
language:en_ZW.UTF-8
session-with-name:Ubuntu Classic (No effects):gnome-session --session=2d-gnome
session-with-name:Ubuntu (Safe Mode):gnome-session -f --session=2d-gnome
session-with-name:Ubuntu Classic:gnome-session --session=classic-gnome
xsession:/etc/X11/Xsession
rating:94

Mogę to zrobić w ten sposób

# nc localhost 9571 | grep rating | cut -d: -f2
94

ale awkzamiast tego można zastosować prostsze rozwiązanie?


To pytanie wydaje się nie na temat, ponieważ dotyczy programowania w interfejsie Awk i jest bardziej odpowiednie na StackOverflow.com
Magellan

Odpowiedzi:


32
$ nc localhost 9571 | awk -F: '/rating/ { print $2 }'

7
Może dawać błędne wyniki, jeśli którakolwiek z wartości lub nazw pól zawiera ciąg „ocena”, tzn. Jedna z nazw sesji zawiera słowo „ocena”. Lepiej:awk -F: '$1 == "rating" {print $2}'
Ingmar Hupp

3
A może awk -F: '/^rating:/ { print $2 }'?
CVn

Wiem o tym, ale dokonuję konwersji na podstawie polecenia PO.
kwanta

@IngmarHupp Myślałem dokładnie tak samo. W rzeczywistości o wiele lepiej jest dopasować dokładnie do tego konkretnego rekordu, że z tą zmianą zredagowałem odpowiedź. Miejmy nadzieję, że pomoże to ludziom nauczyć się efektywniej korzystać z awk.
Dan Molding,

14

Quanta mnie pobił, ale dołączę sedwariant, jeśli masz taką skłonność:

nc localhost 9571 | sed -ne 's/^rating://p'

To samo mówi MadHatter. Twoje obecne rozwiązanie jest całkowicie solidne. (Chociaż chciałbym pozdrowić "^rating:"zamiast słowa, aby upewnić się, że otrzymujesz tylko tę linię, którą chcesz.)


Kocham sed! Jest tak niewykorzystany i niedoceniany ...
Mei

9

Możesz także po prostu użyć powłoki:

nc localhost 9571 | 
while IFS=: read key val; do [[ $key = "rating" ]] && echo "$val"; done

Jest to najszybszy sposób - i zapobiega pojawianiu się jakichkolwiek procesów poza nim nc. Ładny!
Mei

7

tak, możesz (i powinieneś) użyć (jednego) awk zamiast (dwóch) grep i cut:

$ nc localhost 9571 | awk -F: '/^rating:/ { print $2 }'

Pamiętaj, aby dopasować swoją linię tak dobrze, jak to możliwe, aby uniknąć brzydkich błędów.

  • /rating/ Pracuje,
  • /^rating/ jest lepszy (bezpieczniejszy),
  • /^rating:/ jest najlepszy (w tym przypadku).

4

To może:

nc localhost 9571  | awk -F: '{ if ($1 == "rating") print $2 }' 

(Nie wiem, co robisz z localhost powyżej, więc wykorzystałem twój wynik jako dane wejściowe do mojej komendy awk, a następnie zastąpiłem „cat” „nc ...” - ale powinno być w porządku.)

Ale dlaczego miałbyś to zrobić? UNIX polega na tym, aby mieć wiele małych narzędzi, z których każde robi jedną rzecz dobrze, połączonych razem za pomocą potoków, zamiast używać większych narzędzi wielofunkcyjnych. Musisz wybrać pojedynczą pasującą linię, wybierz jedno pole z niej: grepwybiera linie z dopasowaniami i cutwybiera pola z linii wejściowych; są idealne do tego zadania. Ale jeśli naprawdę chcesz zrobić to wszystko w jednym z awk, cóż, proszę bardzo.


Jednym z powodów jest to, że użycie grepi cutwymaga spawnowania dwóch procesów, a użycie awk(lub sed) wymaga tylko jednego. Spawnowanie procesu jest drogie obliczeniowo. Ponadto, w przeciwieństwie do używania perllub ruby(i innych), sedi awksą znacznie lżejsze z przodu.
Mei

2
W porządku, choć zauważam, że rozmiar pliku binarnego awk w moim (F15) systemie wynosi 360948 bajtów, podczas gdy pliki binarne grep i cut razem to 170824. Tak mniej cykli z jednym widelcem + exec, ale więcej pamięci i więcej IO aby pobrać plik binarny z dysku. Szczerze mówiąc, wątpię, aby którekolwiek z tych rozważań miały znaczenie w nowoczesnych systemach, ale jeśli masz zamiar zminimalizować, proszę bardzo!
MadHatter

Foo Bah: dziękuję za twoją propozycję edycji, ale quanta opublikowała później post niż mój, co jest jeszcze bardziej usprawnione niż twoja sugestia. Wolę mój, ponieważ łatwiej jest użytkownikowi awk na poziomie podstawowym zobaczyć, jak to działa, i dlatego odrzuciłem twoją edycję. Ale dziękuję za tę myśl!
MadHatter

3

Chociaż odpowiedź quanty jest najłatwiejsza i ta, którą też napisałbym, założę się, że nie wiedziałeś, że GNU awk (gawk) może również robić sieci ? Możesz napisać całą rzecz za pomocą awk, jeśli naprawdę chcesz:

BEGIN {
    FS = ":"
    f = "/inet/tcp/0/127.0.0.1/9571"
    while ((f |& getline) > 0)
        if ($1 ~ /^rating$/) {print $2}
}

Może to być przydatne, jeśli serwer nie ma zainstalowanego nc, nc ma ograniczone uprawnienia lub jeśli naprawdę lubisz awk.


Oooch Ładny. Sieć i przykład koprocesowania.
Dr Edward Morbius

0

Możesz także użyć sed,

nc localhost 9571 | sed -n "s/^rating:\([\d]*\)/\1/p"

Zapewni to, że „ocena” rozpocznie linię, a cyfry będą następować po rating:


0

Jeśli Perl jest opcją:

nc localhost 9571 | perl -F: -lane 'print $F[1] if /rating/'

-aautosplits każdą linię w @Ftablicy
-F:używa :jako separatora pól, zamiast domyślnej spacji
/rating/zwraca true, jeśli wyrażenie regularne jest
$F[1]drugim elementem @Ftablicy.
Tablice Perla zaczynają się od elementu 0, podczas gdy awk zaczyna się od 1 $

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.