script - Imprimir con sed o awk una línea siguiendo un patrón coincidente
sed reemplazar/ (7)
En realidad sed -n ''/pattern/{n;p}'' filename
fallará si el pattern
coincide con líneas continuous
:
$ seq 15 |sed -n ''/1/{n;p}''
2
11
13
15
Las respuestas esperadas deberían ser:
2
11
12
13
14
15
Mi solución es:
$ sed -n -r ''x;/_/{x;p;x};x;/pattern/!s/.*//;/pattern/s/.*/_/;h'' filename
Por ejemplo:
$ seq 15 |sed -n -r ''x;/_/{x;p;x};x;/1/!s/.*//;/1/s/.*/_/;h''
2
11
12
13
14
15
Explica:
-
x;
: al comienzo de cada línea desde la entrada, use el comandox
para intercambiar los contenidos en elpattern space
yhold space
. -
/_/{x;p;x};
: si elpattern space
, que es elhold space
realidad, contiene_
(esto es solo unindicator
indica si la última línea coincidió con elpattern
o no), utilicex
para intercambiar el contenido real decurrent line
porpattern space
, usep
para imprimircurrent line
, yx
para recuperar esta operación. -
x
: recuperar los contenidos en elpattern space
yhold space
. -
/pattern/!s/.*//
: sicurrent line
NO coincide con elpattern
, lo que significa que NO debemos imprimir la siguiente línea SIGUIENTE, entonces uses/.*//
comandos/.*//
para borrar todo el contenido en elpattern space
. -
/pattern/s/.*/_/
: sicurrent line
coincide con elpattern
, lo que significa que debemos imprimir la siguiente línea SIGUIENTE, entonces debemos establecer unindicator
para indicarle ased
que imprima la línea NEXT, así que uses/.*/_/
para sustituir todo el contenido en elpattern space
por un_
(el segundo comando lo usará para juzgar si la última línea coincide con elpattern
o no). -
h
: sobrescribe elhold space
con los contenidos en elpattern space
; luego, el contenido en elhold space
es^_$
que significa quecurrent line
coincide con elpattern
, o^$
, lo que significa quecurrent line
NO coincide con elpattern
. - el quinto y el sexto paso NO pueden intercambiarse, porque después de
s/.*/_/
, elpattern space
delpattern space
NO puede coincidir/pattern/
, por lo ques/.*//
DEBE ejecutarse.
Me gustaría imprimir una sola línea directamente siguiendo una línea que contenga un patrón coincidente. Mi versión de sed
no tomará la siguiente sintaxis (explota en +1p
.) Que parecería una solución simple:
sed -n ''/ABC/,+1p'' infile
Supongo que awk
sería mejor hacer procesamiento de líneas múltiples, pero no estoy seguro de cómo hacerlo.
Es la línea después de ese partido en la que estás interesado, ¿verdad? En Sed, eso podría lograrse así:
sed -n ''/ABC/{n;p}'' infile
Alternativamente, la opción A de grep puede 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
Puede usar lo siguiente:
$ grep -A 1 "bar" file
bar
baz
$ sed -n ''/bar/{n;p}'' file
baz
Espero que ayude.
Esto podría funcionar para usted (GNU sed):
sed -n '':a;/regexp/{n;h;p;x;ba}'' file
Use la opción sep grep-like y si la línea actual contiene la expresión regular requerida reemplace la línea actual con la siguiente, copie esa línea en el espacio de espera (HS), imprima la línea, cambie el espacio del patrón (PS) para el HS y repetir.
Necesitaba imprimir TODAS las líneas después del patrón (ok Ed, REGEX), así que me decidí por este:
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 una head -1
al final
sed -n ''/pattern/,$p'' | tail -n+2 | head -1 # prints line after pattern
Nunca use la palabra "patrón", ya que es muy ambigua. Siempre use "string" o "regexp" (o en shell "globbing pattern"), lo que sea que realmente quiera decir.
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 N-é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) Imprime todos los registros de algunos regexp:
awk ''/regexp/{f=1}f'' file
b) Imprima todos los registros después de algunos regexp:
awk ''f;/regexp/{f=1}'' file
c) Imprima el N-ésimo registro después de algunas expresiones regulares:
awk ''c&&!--c;/regexp/{c=N}'' file
d) Imprima todos los registros, excepto el N-ésimo registro después de algunos regexp:
awk ''c&&!--c{next}/regexp/{c=N}1'' file
e) Imprima los N registros después de algunos regexp:
awk ''c&&c--;/regexp/{c=N}'' file
f) Imprima todos los registros excepto los N registros después de algunos regexp:
awk ''c&&c--{next}/regexp/{c=N}1'' file
g) Imprima los N registros de algunos regexp:
awk ''/regexp/{c=N}c&&c--'' file
Cambié el nombre de la variable de "f" por "encontrado" a "c" por "conteo" cuando correspondía, ya que eso es más expresivo de lo que realmente es la variable.
Si coincide el patrón, copie la siguiente línea en el buffer del patrón, elimine un retorno, luego déjelo - el efecto secundario es imprimir.
sed ''/pattern/ { N; s/.*/n//; q }; d''
Versión de awk:
awk ''/regexp/ { getline; print $0; }'' filetosearch