È possibile utilizzare Awk?


17

Vorrei ottenere il numero da ratingcome output da questo

# 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

Posso farlo in questo modo

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

ma potrebbe awkessere usato invece per una soluzione più semplice?


Questa domanda sembra fuori tema perché riguarda la programmazione nell'interfaccia di Awk ed è più pertinente su StackOverflow.com
Magellan,

Risposte:


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

7
Può dare risultati errati se uno qualsiasi dei valori o dei nomi dei campi contiene la stringa "rating", ovvero uno dei nomi di sessione contiene la parola "rating". Meglio:awk -F: '$1 == "rating" {print $2}'
Ingmar Hupp il

3
O forse awk -F: '/^rating:/ { print $2 }'?
un CVn

Lo so, ma converto in base al comando del PO.
quanta

@IngmarHupp Ho pensato esattamente la stessa cosa. In effetti è molto meglio abbinare l'esatto record in questione che ho modificato la risposta con questa modifica. Si spera che questo aiuti le persone a imparare a usare awk in modo più efficace.
Dan Molding

14

Quanta mi ha battuto, ma includerò una sedvariante se sei così incline:

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

Idem quello che ha detto MadHatter, però. La tua soluzione attuale è perfettamente sana. (Anche se farei il grep "^rating:"piuttosto che solo la parola per assicurarti di ottenere solo la linea che desideri.)


Io adoro sed! È così sottoutilizzato e sottovalutato ...
Mei,

9

Puoi anche semplicemente usare la shell:

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

Questo è il modo più rapido e impedisce di generare altri processi oltre nc. Bello!
Mei,

7

sì, puoi (e dovresti) usare (uno) awk invece di (due) grep e cut:

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

Assicurati di abbinare la tua linea il più bene possibile per evitare brutti bug.

  • /rating/ lavori,
  • /^rating/ è meglio (più sicuro),
  • /^rating:/ è il migliore (in questo caso).

4

Può:

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

(Non so cosa stai facendo con localhost sopra, quindi ho usato il tuo output come input per il mio comando awk, quindi ho sostituito "cat" con "nc ..." - ma dovrebbe andare bene.)

Ma perché dovresti farlo? Il modo UNIX è di avere molti piccoli strumenti, ognuno dei quali fa bene una cosa, messi insieme tramite tubazioni, piuttosto che usare strumenti multifunzione più grandi. Devi selezionare una singola linea di corrispondenza, selezionare un campo da essa: grepseleziona le linee con le corrispondenze e cutseleziona i campi dalle linee di input; sono perfetti per il compito. Ma se vuoi davvero farlo tutto in uno con Awk, beh, eccoti.


Uno dei motivi è che l'utilizzo grepe la cutgenerazione di due processi richiedono e l'utilizzo awk(o sed) richiede solo uno. La generazione di un processo è computazionalmente costosa. Inoltre, a differenza dell'uso di perlo ruby(et al), sede awksono molto più leggeri nella parte anteriore.
Mei,

2
Abbastanza giusto, anche se noto che la dimensione del binario awk sul mio sistema (F15) è 360948 byte, mentre i binari grep e cut insieme sono 170824. Quindi meno cicli con un solo fork + exec, ma più memoria e più IO per togliere il binario dal disco. Sinceramente, dubito che una qualsiasi di queste considerazioni sia importante per i sistemi moderni, ma se hai intenzione di minimizzare, ecco qua!
MadHatter,

Foo Bah: grazie per la tua proposta di modifica, ma quanti hanno pubblicato un post successivo al mio, che è ancora più snello del tuo suggerimento. Ho preferito il mio perché è più facile per un utente awk entry-level vedere come funziona e quindi rifiutare la modifica. Grazie per il pensiero, però!
MadHatter,

3

Mentre la risposta di Quanta è la più semplice e anche quella che scrivo, scommetto che non sapevi che GNU awk (gawk) può fare anche rete ? Puoi scrivere tutto con awk se vuoi davvero:

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

Questo potrebbe essere utile se un server non ha nc installato, nc ha permessi limitati o se ti piace davvero awk.


Oooh. Bello. Networking e un esempio di coprocessing.
Dr. Edward Morbius,

0

Puoi anche usare sed,

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

Questo farà in modo che "valutazione" inizi la linea e che le cifre seguano il rating:


0

Se Perl è un'opzione:

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

-aSposta automaticamente ogni riga @Fnell'array
-F:utilizza :come separatore di campo, invece del valore predefinito di spazio bianco
/rating/restituisce true se viene trovata la regex
$F[1]è il 2 ° elemento @Fdell'array.
Le matrici Perl iniziano con l'elemento 0, mentre awk inizia con $ 1

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.