bash - una - expresiones regulares unix




¿Cómo obtener la parte del archivo después de la línea que coincide con la expresión grep?(primer partido) (8)

Tengo un archivo con aproximadamente 1000 líneas. Quiero la parte de mi archivo después de la línea que coincide con mi declaración grep.

es decir

$ cat file | grep 'TERMINATE'     // Its found on line 534

Por lo tanto, quiero que el archivo de la línea 535 to line 1000 para su posterior procesamiento.

Cómo lo hago ?


A continuación, se imprimirá la línea que coincide TERMINATE hasta el final del archivo:

sed -n -e '/TERMINATE/,$p'

Explicado: -n desactiva el comportamiento predeterminado de sed de imprimir cada línea después de ejecutar su script en él, -e indicó un script para sed , /TERMINATE/,$ es una selección de rango de dirección (línea) que significa la primera línea que coincide con la expresión regular TERMINAR (como grep) hasta el final del archivo ( $ ), y p es el comando de impresión que imprime la línea actual.

Esto se imprimirá desde la línea que sigue a la línea que coincide TERMINATE hasta el final del archivo:
(desde DESPUÉS de la línea coincidente con EOF, NO incluyendo la línea correspondiente)

sed -e '1,/TERMINATE/d'

Explicado: 1,/TERMINATE/ es una selección de rango de dirección (línea) que significa la primera línea para la entrada a la 1ra línea que coincide con la expresión regular TERMINAR, y d es el comando de borrar que borra la línea actual y salta a la próxima línea. Como el comportamiento predeterminado de sed es imprimir las líneas, imprimirá las líneas después de TERMINATE al final de la entrada.

Editar:

Si quieres las líneas antes de TERMINATE :

sed -e '/TERMINATE/,$d'

Y si desea ambas líneas antes y después de TERMINATE en 2 archivos diferentes en una sola pasada:

sed -e '1,/TERMINATE/w before
/TERMINATE/,$w after' file

Los archivos de antes y después contendrán la línea con terminación, por lo tanto, para procesar cada uno, debe usar:

head -n -1 before
tail -n +2 after

Edit2:

SI no desea codificar los nombres de los archivos en el script sed, puede:

before=before.txt
after=after.txt
sed -e "1,/TERMINATE/w $before
/TERMINATE/,\$w $after" file

Pero luego debe escapar de $ significa la última línea para que el intérprete de comandos no intente expandir la variable $w (tenga en cuenta que ahora usamos comillas dobles alrededor del guión en lugar de comillas simples).

Olvidé decir que la nueva línea es importante después de los nombres de archivo en el script para que sed sepa que los nombres de archivo terminan.


Edición: 2016-0530

Sébastien Clément preguntó: "¿Cómo reemplazarías el TERMINADO codificado por una variable?"

Haría una variable para el texto coincidente y luego lo haría de la misma manera que en el ejemplo anterior:

matchtext=TERMINATE
before=before.txt
after=after.txt
sed -e "1,/$matchtext/w $before
/$matchtext/,\$w $after" file

usar una variable para el texto coincidente con los ejemplos anteriores:

## Print the line containing the matching text, till the end of the file:
## (from the matching line to EOF, including the matching line)
matchtext=TERMINATE
sed -n -e "/$matchtext/,\$p"
## Print from the line that follows the line containing the 
## matching text, till the end of the file:
## (from AFTER the matching line to EOF, NOT including the matching line)
matchtext=TERMINATE
sed -e "1,/$matchtext/d"
## Print all the lines before the line containing the matching text:
## (from line-1 to BEFORE the matching line, NOT including the matching line)
matchtext=TERMINATE
sed -e "/$matchtext/,\$d"

Los puntos importantes sobre la sustitución de texto con variables en estos casos son:

  1. Las variables ( $variablename ) entre single quotes [ ' ] no se "expandirán", pero las variables dentro de double quotes [ " ] lo harán. Por lo tanto, debe cambiar todas las single quotes double quotes si contienen texto que desea reemplazar con una variable.
  2. Los rangos de sed también contienen un $ e inmediatamente son seguidos por una letra como: $p , $d , $w . También se verán como variables a expandir, por lo que debe escapar esos $ caracteres con una barra invertida [ \ ] como: \$p , \$d , \$w .

Alternativas a la excelente respuesta sed de jfgagne, y que no incluyen la línea correspondiente:

  • awk '/TERMINATE/ {y=1;next} y' ( https://.com/a/18166628 )
  • awk '/TERMINATE/ ? c++ : c' awk '/TERMINATE/ ? c++ : c' ( https://.com/a/23984891 )
  • perl -ne 'print unless 1 .. /TERMINATE/' ( https://.com/a/18167194 )

Esta podría ser una forma de hacerlo. Si sabe en qué línea del archivo tiene su palabra grep y cuántas líneas tiene en su archivo:

grep -A466 archivo 'TERMINAR'


Estos imprimirán todas las líneas de la última línea encontrada "TERMINAR" hasta el final del archivo:

LINE_NUMBER=`grep -o -n TERMINATE $OSCAM_LOG|tail -n 1|sed "s/:/ \\'/g"|awk -F" " '{print $1}'`
tail -n +$LINE_NUMBER $YOUR_FILE_NAME

Si entiendo su pregunta correctamente, quiere las líneas después de TERMINATE , sin incluir la línea TERMINAR. awk puede hacer esto de una manera simple:

awk '{if(found) print} /TERMINATE/{found=1}' your_file

Explicación:

  1. Aunque no es la mejor práctica, puedes confiar en el hecho de que todos los valores predeterminados de vars a 0 o la cadena vacía si no están definidos. Entonces, la primera expresión ( if(found) print ) no imprimirá nada para comenzar.
  2. Una vez realizada la impresión, verificamos si esta es la línea de inicio (que no debe incluirse).

Esto imprimirá todas las líneas después de TERMINATE -line.

Generalización:

  • Tiene un archivo con líneas de inicio y final y quiere las líneas entre esas líneas excluyendo el inicio y las líneas finales .
  • Las líneas de inicio y fin se pueden definir con una expresión regular que coincida con la línea.

Ejemplo:

$ cat ex_file.txt 
not this line
second line
START
A good line to include
And this line
Yep
END
Nope more
...
never ever
$ awk '/END/{found=0} {if(found) print} /START/{found=1}' ex_file.txt 
A good line to include
And this line
Yep
$

Explicación:

  1. Si se encuentra la línea final, no se debe realizar ninguna impresión. Tenga en cuenta que esta comprobación se realiza antes de la impresión real para excluir la línea final del resultado.
  2. Imprime la línea actual si está establecido.
  3. Si se encuentra la línea de inicio , establezca found=1 para que se impriman las siguientes líneas. Tenga en cuenta que esta comprobación se realiza después de la impresión real para excluir la línea de inicio del resultado.

Notas:

  • El código se basa en el hecho de que todos los awk-vars por defecto son 0 o la cadena vacía si no está definida. Esto es válido, pero puede no ser la mejor práctica, así que podría agregar un BEGIN{found=0} al comienzo de la expresión awk.
  • Si se encuentran múltiples bloques de inicio y fin , todos se imprimen.

Si por algún motivo, desea evitar el uso de sed, lo siguiente imprimirá la línea correspondiente TERMINATE hasta el final del archivo:

tail -n "+$(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)" file

y lo siguiente imprimirá desde la siguiente línea que coincide TERMINATE hasta el final del archivo:

tail -n "+$(($(grep -n 'TERMINATE' file | head -n 1 | cut -d ":" -f 1)+1))" file

Se necesitan 2 procesos para hacer lo que sed puede hacer en un proceso, y si el archivo cambia entre la ejecución de grep y tail, el resultado puede ser incoherente, por lo que recomiendo usar sed. Además, si el archivo no contiene TERMINATE , el primer comando falla.


Use la expansión del parámetro bash como la siguiente:

content=$(cat file)
echo "${content#*TERMINATE}"

grep -A 10000000 archivo 'TERMINAR'

  • es mucho, mucho más rápido que sed, trabajando especialmente en archivos realmente grandes. Funciona hasta 10 millones de líneas (o lo que sea que coloques) por lo que no hay daño en hacer que este sea lo suficientemente grande como para manejar cualquier cosa que golpees.






grep