Peut-on utiliser awk à la place?


17

Je voudrais obtenir le numéro ratingde cette sortie

# 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

Je peux le faire comme ça

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

mais pourrait awkêtre utilisé à la place pour une solution plus simple?


Cette question semble être hors sujet car elle concerne la programmation dans l'interface Awk et est plus pertinente sur StackOverflow.com
Magellan

Réponses:


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

7
Peut donner des résultats incorrects si l'une des valeurs ou des noms de champ contient la chaîne "rating", c'est-à-dire que l'un des noms de session contient le mot "rating". Mieux:awk -F: '$1 == "rating" {print $2}'
Ingmar Hupp

3
Ou peut awk -F: '/^rating:/ { print $2 }'- être ?
un CVn

Je le sais, mais je convertis en fonction de la commande de l'OP.
quanta

@IngmarHupp J'ai pensé exactement la même chose. Il est en fait tellement préférable de faire correspondre sur l'enregistrement exact en question que j'ai modifié la réponse avec ce changement. J'espère que cela aidera les gens à apprendre à utiliser awk plus efficacement.
Dan Moulding du

14

Quanta m'a battu, mais je vais inclure une sedvariante si vous êtes enclin à cela:

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

Idem cependant ce que MadHatter a dit. Votre solution actuelle est parfaitement solide. (Bien que je préfère "^rating:"le mot plutôt que le mot pour vous assurer d'obtenir uniquement la ligne souhaitée.)


J'adore sed! Il est tellement sous-utilisé et sous-estimé ...
Mei

9

Vous pouvez également simplement utiliser le shell:

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

C'est le moyen le plus rapide - et empêche la génération de processus au-delà nc. Agréable!
Mei

7

oui, vous pouvez (et devriez) utiliser (un) awk au lieu de (deux) grep et cut:

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

Assurez-vous de faire correspondre votre ligne aussi bien que possible pour éviter les bugs laids.

  • /rating/ travaux,
  • /^rating/ c'est mieux (plus sûr),
  • /^rating:/ est le meilleur (dans ce cas).

4

Ça peut:

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

(Je ne sais pas ce que vous faites avec localhost ci-dessus, alors utilisez votre sortie comme entrée pour ma commande awk, puis remplacez le "cat" par "nc ..." - mais ça devrait aller.)

Mais pourquoi feriez-vous cela? La méthode UNIX consiste à disposer de nombreux petits outils, chacun faisant bien une chose, assemblés via des pipelines, plutôt que d'utiliser des outils multifonctions plus grands. Vous devez sélectionner une seule ligne correspondante, le champ de sélection de celui-ci: grepsélectionne les lignes avec des correspondances, et cutsélectionne les champs des lignes d'entrée; ils sont parfaits pour la tâche. Mais si vous voulez vraiment tout faire en un avec awk, eh bien, c'est parti.


L'une des raisons est que l'utilisation grepet cutnécessite la génération de deux processus, et l'utilisation awk(ou sed) n'en requiert qu'un. La création d'un processus coûte cher en calcul. En outre, contrairement à l' utilisation perlou ruby(et al), sedet awksont beaucoup plus léger avant vers le haut.
Mei

2
Assez juste, bien que je note que la taille du binaire awk sur mon système (F15) est de 360948 octets, tandis que les binaires grep et cut ensemble sont 170824. Donc moins de cycles avec un seul fork + exec, mais plus de mémoire et plus d'E / S pour retirer le disque binaire. Honnêtement, je doute que l'une de ces considérations soit importante pour les systèmes modernes, mais si vous voulez minimiser, c'est parti!
MadHatter

Foo Bah: merci pour votre proposition de modification, mais quanta a fait un post plus tard que le mien qui est encore plus rationalisé que votre suggestion. J'ai préféré le mien car il est plus facile pour un utilisateur awk d'entrée de gamme de voir comment cela fonctionne, et j'ai donc rejeté votre modification. Merci pour la pensée, cependant!
MadHatter

3

Bien que la réponse de quanta soit la plus simple et celle que j'écrirais aussi, je parie que vous ne saviez pas que GNU awk (gawk) peut aussi faire du réseautage ? Vous pouvez écrire le tout avec awk si vous voulez vraiment:

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

Cela peut être utile si un serveur n'a pas installé nc, nc a des perms restreints ou si vous aimez vraiment awk.


Oooh. Agréable. Mise en réseau et un exemple de coprocessing.
Dr.Edward Morbius

0

Vous pouvez également utiliser sed,

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

Cela permettra de s'assurer que "note" commence la ligne, et que les chiffres suivent le rating:


0

Si Perl est une option:

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

-afractionne automatiquement chaque ligne dans le @Ftableau
-F:utilise :comme séparateur de champ, au lieu de la valeur par défaut des espaces,
/rating/renvoie true si l'expression régulière est trouvée
$F[1]est le 2e élément du @Ftableau.
Les tableaux Perl commencent par l'élément 0, tandis que awk commence par $ 1

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.