Imprimir con sed o awk una línea siguiendo un patrón coincidente

Resuelto user1537723 asked hace 11 años • 0 respuestas

Pregunta: Me gustaría imprimir una sola línea directamente después de una línea que contiene un patrón coincidente.

Mi versión de sedno adoptará la siguiente sintaxis (falla +1p), lo que parecería una solución simple:

sed -n '/ABC/,+1p' infile

Supongo awkque sería mejor realizar un procesamiento multilínea, pero no estoy seguro de cómo hacerlo.

user1537723 avatar Jul 28 '13 20:07 user1537723
Aceptado

Nunca utilice la palabra "patrón" en este contexto ya que es ambigua. Utilice siempre "cadena" o "expresa regular" (o en shell "patrón global"), lo que realmente quiera decir. Consulte ¿Cómo encuentro el texto que coincide con un patrón? para más información sobre eso.

La respuesta específica que desea es:

awk 'f{print;f=0} /regexp/{f=1}' file

o especializando la solución más general del enésimo registro después de una expresión regular (modismo "c" a continuación):

awk 'c&&!--c; /regexp/{c=1}' file

Los siguientes modismos describen cómo seleccionar un rango de registros dada una expresión regular específica para que coincida:

a) Imprima todos los registros de alguna expresión regular:

awk '/regexp/{f=1}f' file

b) Imprima todos los registros después de alguna expresión regular:

awk 'f;/regexp/{f=1}' file

c) Imprima el enésimo registro después de alguna expresión regular:

awk 'c&&!--c;/regexp/{c=N}' file

d) Imprima todos los registros excepto el enésimo registro después de alguna expresión regular:

awk 'c&&!--c{next}/regexp/{c=N}1' file

e) Imprima los N registros después de alguna expresión regular:

awk 'c&&c--;/regexp/{c=N}' file

f) Imprima todos los registros excepto los N registros después de alguna expresión regular:

awk 'c&&c--{next}/regexp/{c=N}1' file

g) Imprima los N registros de alguna expresión regular:

awk '/regexp/{c=N}c&&c--' file

Cambié el nombre de la variable de "f" para "encontrado" a "c" para "recuento" cuando correspondía, ya que eso expresa mejor lo que realmente ES la variable.

fes la abreviatura de found. Es un indicador booleano que establezco en 1 (verdadero) cuando encuentro una cadena que coincide con la expresión regular regexp en la entrada ( /regexp/{f=1}). El otro lugar que ve fpor sí solo en cada secuencia de comandos es que se prueba como una condición y, cuando es verdadero, hace que awk ejecute su acción predeterminada de imprimir el registro actual. Entonces, los registros de entrada solo obtienen salida después de que veamos la expresión regular y la establezcamos fen 1/verdadero.

c && c-- { foo }significa "si ces distinto de cero, disminúyelo y si aún es distinto de cero, ejecútelo foo", por lo que si ccomienza en 3, se reducirá a 2 y luego foose ejecutará, y en la siguiente línea de entrada cahora es 2, por lo que se reducirá a 1 y luego foose ejecutará nuevamente, y en la siguiente línea de entrada cahora es 1, por lo que se reducirá a 0, pero esta vez foono se ejecutará porque 0 es una condición falsa. Lo hacemos c && c--en lugar de simplemente realizar pruebas para c-- > 0no encontrarnos con un caso con un archivo de entrada enorme donde cllega a cero y continúa disminuyendo con tanta frecuencia que se ajusta y vuelve a ser positivo.

Ed Morton avatar Jul 28 '2013 23:07 Ed Morton

Es la línea después de ese partido lo que te interesa, ¿verdad? En sed, eso podría lograrse así:

sed -n '/ABC/{n;p}' infile

Alternativamente, la opción A de grep podría ser lo que estás buscando.

-A NUM, Print NUM lines of trailing context after matching lines.

Por ejemplo, dado el siguiente archivo de entrada:

foo
bar
baz
bash
bongo

Podrías usar lo siguiente:

$ grep -A 1 "bar" file
bar
baz
$ sed -n '/bar/{n;p}' file
baz
chooban avatar Jul 28 '2013 13:07 chooban

Necesitaba imprimir TODAS las líneas después del patrón (ok Ed, REGEX), así que me decidí por esta:

sed -n '/pattern/,$p' # prints all lines after ( and including ) the pattern

Pero como quería imprimir todas las líneas DESPUÉS (y excluir el patrón)

sed -n '/pattern/,$p' | tail -n+2  # all lines after first occurrence of pattern

Supongo que en tu caso puedes agregar un head -1al final.

sed -n '/pattern/,$p' | tail -n+2 | head -1 # prints line after pattern

Y realmente debería incluir el comentario de tlwhitec en esta respuesta (ya que su enfoque sed-strict es más elegante que mis sugerencias):

sed '0,/pattern/d' 

El script anterior elimina cada línea comenzando con la primera y terminando en (e incluyendo) la línea que coincide con el patrón. Todas las líneas posteriores se imprimen.

Mark avatar Jun 24 '2016 19:06 Mark

Versión awk:

awk '/regexp/ { getline; print $0; }' filetosearch
tue avatar Jul 28 '2013 15:07 tue