Devuelve solo la parte de una línea después de un patrón coincidente

109

Entonces, abrir un archivo con caty luego usarlo greppara obtener líneas coincidentes solo me lleva muy lejos cuando estoy trabajando con el conjunto de registros particular con el que estoy tratando. Necesita una forma de hacer coincidir las líneas con un patrón, pero solo para devolver la parte de la línea después de la coincidencia. La porción antes y después del partido variará constantemente. He jugado con sedo awk, pero no he podido descubrir cómo filtrar la línea para eliminar la parte antes del partido, o simplemente devolver la parte después del partido, funcionará. Este es un ejemplo de una línea que necesito filtrar:

2011-11-07T05:37:43-08:00 <0.4> isi-udb5-ash4-1(id1) /boot/kernel.amd64/kernel: [gmp_info.c:1758](pid 40370="kt: gmp-drive-updat")(tid=100872) new group: <15,1773>: { 1:0-25,27-34,37-38, 2:0-33,35-36, 3:0-35, 4:0-9,11-14,16-32,34-38, 5:0-35, 6:0-15,17-36, 7:0-16,18-36, 8:0-14,16-32,34-36, 9:0-10,12-36, 10-11:0-35, 12:0-5,7-30,32-35, 13-19:0-35, 20:0,2-35, down: 8:15, soft_failed: 1:27, 8:15, stalled: 12:6,31, 20:1 }

La porción que necesito es todo después de "estancado".

El trasfondo detrás de esto es que puedo descubrir con qué frecuencia algo se detiene:

cat messages | grep stalled | wc -l

Lo que necesito hacer es averiguar cuántas veces se ha estancado un determinado nodo (indicado por la parte antes de cada dos puntos después de "estancado"). no hay paradas, lo que no me ayuda. Necesito filtrar solo la parte detenida para poder buscar un nodo específico de los que se han estancado.

Para todos los efectos, este es un sistema freebsd con utilidades centrales GNU estándar, pero no puedo instalar nada extra para ayudar.

MaQleod
fuente
@Gilles, extraño cómo eso no apareció cuando busqué, aunque no usé el título con el que finalmente fui ... pero no apareció en la pantalla debajo de mi título. De todos modos, aparte de eso, eso podría llevarme a donde quiero, aunque necesito toda la línea después del partido, no la primera palabra, pero podría no tener mucho cambio.
MaQleod
Su título apestaba. Robé el tuyo, que es muy agradable. Tome la sedsolución y no trate los espacios en blanco especialmente.
Gilles
@Gilles, eso es algo que no estoy completamente seguro de cómo hacer. Todavía estoy aprendiendo sed.
MaQleod
similar a unix.stackexchange.com/questions/24089/… también.
Tim Kennedy el
1
@ shaa0601 No entiendo tu pregunta, es especialmente difícil de seguir en un comentario sin formato. Haga una nueva pregunta independiente.
Gilles

Respuestas:

141

La herramienta canónica para eso sería sed.

sed -n -e 's/^.*stalled: //p'

Explicación detallada:

  • -n significa no imprimir nada por defecto.
  • -e es seguido por un comando sed.
  • s es el comando de reemplazo de patrón.
  • La expresión regular ^.*stalled:coincide con el patrón que está buscando, más cualquier texto anterior (es .*decir, cualquier texto, con una inicial ^que indique que la coincidencia comienza al comienzo de la línea). Tenga en cuenta que si stalled:ocurre varias veces en la línea, esto coincidirá con la última ocurrencia.
  • La coincidencia, es decir, todo en la línea hasta stalled:, se reemplaza por la cadena vacía (es decir, se elimina).
  • El último pmedio para imprimir la línea transformada.

Si desea retener la parte correspondiente, use una referencia inversa: \1en la parte de reemplazo se designa lo que está dentro de un grupo \(…\)en el patrón. Aquí, podría stalled:volver a escribir en la parte de reemplazo; Esta característica es útil cuando el patrón que está buscando es más general que una cadena simple.

sed -n -e 's/^.*\(stalled: \)/\1/p'

A veces querrás eliminar la parte de la línea después del partido. Puede incluirlo en la coincidencia al incluirlo .*$al final del patrón (cualquier texto .*seguido del final de la línea $). A menos que coloque esa parte en un grupo al que hace referencia en el texto de reemplazo, el final de la línea no estará en la salida.

Como ilustración adicional de grupos y referencias, este comando intercambia la parte anterior al partido y la parte posterior al partido.

sed -n -e 's/^\(.*\)\(stalled: \)\(.*\)$/\3\2\1/p'
Gilles
fuente
He probado los dos primeros ejemplos y parece que se cuelga. No recibo un mensaje de error, ni recibo un nuevo mensaje, simplemente nada.
MaQleod
2
@MaQleod Oh, está esperando la entrada en la entrada estándar, que aquí es el terminal porque no lo ha redirigido. Aquí haría una redirección de entrada sed … <messages, ya que desea procesar datos de un archivo. Para actuar sobre los datos producidos por otro comando, tendrá que utilizar un tubo: somecommand | sed ….
Gilles
1
a la derecha, final del día apagón allí. comando funciona perfectamente, gracias.
MaQleod
1
La mejor explicación de sed que he visto hasta ahora, ¡gracias!
Jon Wadsworth
1
@ungalcrys ¿Versión más corta de qué? Esto no es equivalente a ninguno de los comandos en mi respuesta. Recomiendo escribirlo sed 's/^.*stalled//'ya que -res específico de Linux y no funciona en otros sistemas como macOS y aquí no obtienes ningún beneficio.
Gilles
72

La otra herramienta canónica que ya usa grep:

Por ejemplo:

grep -o 'stalled.*'

Tiene el mismo resultado que la segunda opción de Gilles:

sed -n -e 's/^.*\(stalled: \)/\1/p'

La -obandera devuelve la --only-matchingparte de la expresión, por lo que no toda la línea que, por supuesto, normalmente se hace con grep.

Para eliminar el "estancado:" de la salida, podemos usar una tercera herramienta canónica, cortar:

grep -o 'stalled.*' | cut -f2- -d:

El cutcomando usa delimitador :e imprime el campo 2 hasta el final. Es una cuestión de preferencia, por supuesto, pero la cutsintaxis me parece muy fácil de recordar.

Anne van Rossum
fuente
1
¡Gracias por mencionar la -oopción! Quería señalar que grepno reconoce el \ncomo una nueva línea, por lo que su primer ejemplo solo coincide con el primer npersonaje. Por ejemplo, echo "Hello Anne" | grep -o 'A[^\n]*'devuelve la cadena A. Sin embargo, echo "Hello Anne" | grep -o 'A.*'devuelve el esperado Anne, ya que .coincide con cualquier carácter excepto la nueva línea.
adamlamar
1
Tenga en cuenta que @poige elimina las comillas alrededor del cutdelimitador -d':'. Me resulta más fácil recordarlo con comillas, por ejemplo, con -d' 'o -d';'.
Anne van Rossum
Según su hallazgo, también debería ser más fácil recordar usar comillas -f 2. En serio, ¿por qué no?
poige
Porque un delimitador como un punto y coma en ;lugar de dos puntos :se interpretará de manera diferente si no se cita. Por supuesto que es un comportamiento lógico, pero aún así me gusta confiar en la memoria muscular. No me gusta citar el delimitador una vez, pero no la otra. Solo preferencia personal, como dije antes: más fácil de recordar.
Anne van Rossum
el período que es parte del .*necesario, funcionó bien para mí: cat filename | grep 'Return only this line xyz text' | grep -o 'xyz.*' regresaxyz text
ron
4

Solía ifconfig | grep eth0 | cut -f3- -d:tomar esto

    [root@MyPC ~]# ifconfig
    eth0  Link encap:Ethernet  HWaddr AC:B4:CA:DD:E6:F8
          inet addr:192.168.0.2  Bcast:192.168.0.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:78998810244 errors:1 dropped:0 overruns:0 frame:1
          TX packets:20113430261 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:110947036025418 (100.9 TiB)  TX bytes:15010653222322 (13.6 TiB)

y hacer que se vea así

    [root@MyPC ~]# ifconfig | grep eth0 | cut -f3- -d:
    C4:7A:4D:F6:B8
Luis perez
fuente
2
¿Responde esto la pregunta?
Stephen Rauch
1
Puede usar cat /sys/class/net/*/address, no requiere análisis.
Anne van Rossum
1

Otra herramienta canónica que consideró awkpodría usarse con la siguiente línea:

awk -F"stalled" '/stalled/{print $2}' messages

Explicación detallada:

  • -Fdefine un separador para la línea, es decir, "estancado". Todo antes del separador se trata con $1y todo después con $2.
  • /reg-ex/ Busca la expresión regular coincidente, en este caso "estancada".
  • {print $<n>}- imprime n columna. Dado que su separador se define como bloqueado, todo lo que se encuentre después de bloqueado se considera la segunda columna.
robertm.tum
fuente