Imprimir línea después de la enésima aparición de una coincidencia


8

Estoy buscando mostrar la línea 4598 en el siguiente archivo. Efectivamente, quiero mostrar la línea DESPUÉS de la enésima aparición de una coincidencia. En este caso, la línea después de la tercera aparición de <Car>. ¿Cómo hago esto?

<Car>
10456
</Car>
<Car>
70192
</Car>
<Car>
4598
</Car>

1
Si bien es posible lograr lo que desea usar sed, awko incluso grep, es aconsejable utilizar un analizador XML.
devnull

XML solo se usó para el ejemplo, el texto puede tener cualquier formato
DJ180

Respuestas:


10
awk -v n=3 '/<Car>/ && !--n {getline; print; exit}'

O:

awk '/<Car>/ && ++n == 3 {getline; print; exit}'

Para pasar el patrón de búsqueda como una variable:

var='<car>'
PATTERN="$var" awk -v n=3 '
  $0 ~ ENVIRON["PATTERN"] && ++n == 3 {getline; print; exit}'

Aquí, el uso en ENVIRONlugar de -vas -vexpande las secuencias de escape de barra invertida y las barras invertidas a menudo se encuentran en expresiones regulares (por lo que deberían duplicarse -v).

GNU awk4.2 o superior le permite asignar variables como expresiones regulares de tipo fuerte . Mientras su modo POSIX no esté habilitado (por ejemplo, a través de la $POSIXLY_CORRECTvariable de entorno, puede hacer lo siguiente:

# GNU awk 4.2 or above only, when not in POSIX mode
gawk -v n=3 -v pattern="@/$var/" '
  $0 ~ pattern && ++n == 3 {getline; print; exit}'

Cómo pasar el patrón de búsqueda también como una variable en el comando anterior
WanderingMind

@WanderingMind, ver edición.
Stéphane Chazelas

4

Aquí hay una perl:

perl -ne 'print && exit if $c==3; $c++ if /<Car>/;' file 

Con GNU grep, también puede analizar su salida como:

grep -A 1 -m 3 '<Car>' file | tail -n 1

De man grep:

-A NUM, --after-context=NUM
          Print NUM lines of trailing context after matching lines.  
          Places a line containing a group separator (--) between 
          contiguous  groups  of  matches.          
-m NUM, --max-count=NUM
          Stop reading a file after NUM matching lines.  

3

Con GNU awkusted puede hacer:

gawk -v RS='</Car>' 'NR==3 && $0=$2' inputFile

1

Aquí hay otra forma con sed:

sed -n '/<Car>/{x;/.\{2\}/{x;$!{n;p};q};s/.*/&./;x}' infile

Esto está usando el espacio de espera para contar.
Cada vez que encuentra una línea que coincide <Car>, xcambia los búferes y comprueba si hay exactamente N-1 de un carácter en el búfer de retención. Si la verificación es exitosa, e xcambia nuevamente, y si no está en la última línea, tira de la nlínea de extensión y penjuaga el espacio del patrón.q cierra. De lo contrario, solo agrega otro .carácter al espacio de espera y e xvuelve a cambiar.


0

Aquí hay una solución de línea de comando simple.

grep -F -A1 '<Car>' filename | grep -E -v '<Car>|--' | tail -n +3 |head -n +1

Si cambia el valor de +3 después tail, puede especificar cualquier enésima línea.


No estoy seguro de por qué agregó las etiquetas, sed, awk, etc. Si desea una solución utilizando una aplicación específica, utilidad, entonces debe especificar esto en cuestión o título.
bsd
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.