¿Se puede usar awk en su lugar?

17

Me gustaría obtener el número ratingcomo resultado de esto

# 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

Puedo hacerlo asi

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

pero podría awkusarse en su lugar para una solución más simple?

Sandra
fuente
Esta pregunta parece estar fuera de tema porque se trata de programar en la interfaz Awk y es más relevante en StackOverflow.com
Magellan

Respuestas:

32
$ nc localhost 9571 | awk -F: '/rating/ { print $2 }'
quanta
fuente
77
Puede dar resultados incorrectos si alguno de los valores o nombres de campo contiene la cadena "rating", es decir, uno de los nombres de sesión contiene la palabra "rating". Mejor:awk -F: '$1 == "rating" {print $2}'
Ingmar Hupp
3
O tal vez awk -F: '/^rating:/ { print $2 }'?
un CVn
Lo sé, pero convierto según el comando del OP.
quanta
@IngmarHupp Pensé exactamente lo mismo. De hecho, es mucho mejor que coincida con el registro exacto en cuestión que he editado la respuesta con este cambio. Con suerte, esto ayudará a las personas a aprender a usar awk de manera más efectiva.
Dan Molding el
14

Quanta me ganó, pero incluiré una sedvariante si estás inclinado de esa manera:

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

Sin embargo, lo mismo dice MadHatter. Su solución actual es perfectamente sólida. (Aunque preferiría en "^rating:"lugar de solo la palabra para asegurarme de que solo obtenga la línea que desea).

SmallClanger
fuente
Amor I sed! Está tan subutilizado y subestimado ...
Mei
9

También puedes usar el shell:

nc localhost 9571 | 
while IFS=: read key val; do [[ $key = "rating" ]] && echo "$val"; done
Glenn Jackman
fuente
Esta es la forma más rápida, y evita que se generen procesos más allá nc. ¡Agradable!
Mei
7

Sí, puede (y debe) usar (uno) awk en lugar de (dos) grep y cortar:

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

Asegúrese de hacer coincidir su línea lo mejor que pueda para evitar errores feos.

  • /rating/ trabajos,
  • /^rating/ es mejor (más seguro)
  • /^rating:/ es lo mejor (en este caso).
Michał Šrajer
fuente
4

Puede:

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

(No sé lo que está haciendo con localhost arriba, así que usé su salida como entrada para mi comando awk, luego reemplacé el "gato" con "nc ...", pero debería estar bien).

¿Pero por qué harías esto? La forma UNIX es tener muchas herramientas pequeñas, cada una de las cuales hace bien una cosa, unidas a través de tuberías, en lugar de usar herramientas multifunción más grandes. Debe seleccionar una sola línea coincidente, seleccione un campo a partir de allí: grepselecciona líneas con coincidencias y cutselecciona campos de las líneas de entrada; Son perfectos para la tarea. Pero si realmente quieres hacerlo todo junto con awk, bueno, ahí lo tienes.

MadHatter
fuente
Una razón es que usar grepy cutrequiere generar dos procesos, y usar awk(o sed) requiere solo uno. Generar un proceso es computacionalmente costoso. Además, a diferencia de usar perlo ruby(et al), sedy awkson mucho más ligeros por adelantado.
Mei
2
Es justo, aunque noto que el tamaño del binario awk en mi sistema (F15) es 360948 bytes, mientras que los binarios grep y cut juntos son 170824. Por lo tanto, menos ciclos con solo una bifurcación + ejecutivo, pero más memoria y más IO para sacar el binario del disco. Honestamente, dudo que alguna de estas consideraciones sea importante en los sistemas modernos, pero si le importa minimizar, ¡ya está!
MadHatter
Foo Bah: gracias por su propuesta de edición, pero quanta hizo una publicación posterior a la mía, que es aún más simplificada que su sugerencia. Preferí el mío porque es más fácil para un usuario awk de nivel de entrada ver cómo funciona y, por lo tanto, rechazó su edición. Gracias por el pensamiento, sin embargo!
MadHatter
3

Si bien la respuesta de quanta es la más fácil y la que yo también escribiría, apuesto a que no sabías que GNU awk (gawk) también puede hacer redes . Puedes escribir todo con awk si realmente quieres:

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

Esto puede ser útil si un servidor no tiene nc instalado, nc tiene permisos restringidos o si realmente le gusta awk.

Mark McKinstry
fuente
Oooh Agradable. Redes y un ejemplo de coprocesamiento.
Dr. Edward Morbius
0

También puedes usar sed,

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

Esto asegurará que la "calificación" comience la línea, y que los dígitos sigan el rating:

Sirch
fuente
0

Si Perl es una opción:

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

-alas divisiones automáticas de cada línea en la @Fmatriz se
-F:utilizan :como separador de campo, en lugar del valor predeterminado de espacios en blanco
/rating/devuelve verdadero si se encuentra que la expresión regular
$F[1]es el segundo elemento de la @Fmatriz.
Las matrices de Perl comienzan con el elemento 0, mientras que awk comienza con $ 1

Chris Koknat
fuente