GREP y SED
Antecedentes: editor de text ED
ed es un editor de línea. Fue desarrollado en una época en la que las terminales de computadora (teclado y pantalla) no eran lo más corriente. Usualmente se utilizaba una teletipo (una suerte de máquina de escribir: teclado con impresión en papel fanfold),para comunicarse con la computadora y por lo tanto no era posible desplegar datos en una pantalla. Para ahorrar papel, el contenido de un archivo se ingresaba una línea por vez y se empleaban comandos sofisticados para realizar la edición. De esta aplicación surgen maneras muy inteligentes y eficientes de procesar textos. Muchas de las ideas incorporadas a ed para trabajar eficientemente con textos migrarían a programas como vi, grep y sed.
Referencias:
Tutorial muy básico de ed:
Ed tiene 2 modos: comando e inserción
En el modo comando, la sintaxis para ingresar comandos es:
[ dirección[,dirección]]comando[parámetros]
donde lo que aparece entre paréntesis rectos es opcional
Los comandos suelen limitarse a una letra. Las direcciones corresponden a números de línea, los parámetros son datos adicionales que en ocasiones el comando requiere.
ed siempre arranca en modo comando. Para pasar a modo insertar o agregar, deben usarse los comandos i o a. Si se usa el comando i, se inserta texto antes de la línea corriente. Si se usa el comando a, se agrega texto luego de la línea corriente. Para terminar de insertar o agregar texto, se debe insertar una . aislado en una línea. Eso hace que ed pase del modo inserción a modo comando nuevamente.
Sólo es posible ingresar comandos en el modo comando. Mientras que se está en el modo inserción, todo el texto que se inserte pasa a formar parte del archivo que se esté editando.
Mientras se está editando el archivo, el texto existe en un “buffer” (podemos pensarlo como un área de trabajo, en la memoria de la computadora). Para salvar ese texto usamos el comando w:
- w salva el archivo a disco
- w nombre salva el contenido del archivo a disco con el nombre que le pongamos
Para salir de ed podemos usar el comando q. Si no queremos salvar el contenido del archivo, pero queremos salir de ed, podemos forzar la salida con Q.
Para distinguir cuando estamos en modo comando
o modo inserción
, podemos activar un prompt
, con el comando P. de esa manera aparece un *
(asterisco), que marca que estamos en modo comando
.
Direccionamiento:
Cómo elegimos la línea corriente:
- Si ingresamos un número, esa línea de texto pasa a ser la línea corriente.
- Ingresando , o p o . se imprime en pantalla el contenido de la línea corriente.
- Ingresando n, se imprime en pantalla el contenido de la línea corriente, acompañada del correspondiente número de línea.
Por defecto, cualquier comando que se ejecute, tiene efecto únicamente sobre la línea corriente. Para que el comando actúe sobre varias líneas, hay que especificar un rango de direcciones: [dirección[,dirección]]
Rangos de líneas y cambio de línea corriente:
- 3 nos movemos a la tercer línea (pasa a ser la línea corriente)
- $ vale por la última línea: la última línea pasa a ser la línea corriente
- +2 nos movemos 2 líneas hacia adelante
- -4 nos movemos 4 líneas hacia atrás
- 3,7 vale por el rango de líneas desde la tercera a la séptima
- . vale por la línea corriente
- , vale por todo el rango de líneas. Es equivalente a 1,$
- .,$ vale por el rango que va de la línea corriente a la última
- /regex/ nos movemos a la siguiente línea que contenga la expresión regular
- ?regex? nos movemos a la línea anterior que contenga la expresión regular
Comando habituales:
- p imprime la línea corriente
- ,p imprime todas las líneas
- ,n idem, pero incluyendo el número de línea adelante
- 3,7n imprimir las líneas de la 3 a la 7 inclusive
- /regex/ hace corriente la primer línea que contenga la expresión regular
- g/regex/p imprime las líneas que contengan la expresión regular
Cambiando una línea:
- 3c pasa a modo inserción y sustituye la línea 3 por el texto ingresado. Se sale del modo inserción con . aislado
Borrando una línea (o rango de líneas):
- 3d borra (delete) la línea 3
- 3,7d borra las líneas 3 a 7 inclusive
Moviendo líneas:
- 3m1 mueve la línea 3 a la primer posición
- 1m$ mueve la primer línea al último lugar
Sustituyendo texto:
- s/regex/texto/ sustituye la primer ocurrencia de
regex
por el correspondientetexto
en la línea corriente.
Parámetros adicionales:
- s/regex/texto/3 sustituye la tercer ocurrencia de
regex
(si regex está al menos 3 veces presente en la línea - s/regex/texto/g sustituye todas las veces que aparezca
regex
- 3s/regex/texto/g sustituye todas las veces que aparezca
regex
en la línea 3 - 3,7s/regex/texto/g sustituye todas las veces que aparezca
regex
entre las líneas 3 y 7 - ,s/regex/texto/g sustituye
regex
en todo el archivo
GREP
El comando g/re/p de ed es el origen del nombre del comando grep. Sirve para buscar dentro de uno o más archivos, líneas que contengan una determinada expresión regular.
grep "regex" archivo grep -e "regex" archivo
grep puede invocarse también como egrep fgrep o rgrep.
- egrep es equivalente a grep -E: extended
regex
- fgrep es equivalente a grep -F: fixed string (no se interpreta como
regex
) - rgrep es equivalente a grep -r: recursive
Opciones habituales:
- -i: ignore case
- -v: invert match (muestra las líneas que NO contienen
regex
- -c: sólo muestra cuantas líneas contienen
regex
- -o: sólo imprime la parte de la línea que cumple con
regex
- -q: quiet, no muestra nada, exit code 0 si encontró algo (se puede usar en setencias if)
- -H: imprime el nombre del archivo donde encontró
regex
- -n: imprime el número de línea donde encontró
regex
- –color=auto: resalta
regex
con color - -A NUM: imprime la línea que contiene
regex
y lasNUM
líneas siguientes (after) - -B NUM: idem pero las
NUM
anteriores (before) - -r: busca recursivamente en todos los archivos del path y sus subdirectorios
- -E: habilita el uso de expresiones regulares extendidas (comparar -F, -P y -G)
Expresiones Regulares
La expresión regular más sencilla es un texto cualquiera.
grep "texto" archivo grep -i "texto" archivo
Si usamos fgrep o grep -F, entonces se puede emplear cualquier caracter en en el “texto”
que se busca. De lo contrario, hay algunos caracteres que tienen significado especial (metacaracteres). Si se desea incluir un metacaracter en la búsqueda, hay que anular su significado, antecediéndolo con \
.
Metacaracteres y su uso: 1) conjuntos de caracteres:
- […] vale por algunos de los caracteres representados por
…
grep if if.txt
grep "[iI]f" if.txt grep -i if if.txt
- [^…] niega los caracteres especificados entre paréntesis rectos (complemento)
- [.-.] rangos de caracteres. Ejemplo: [a-d6-9] vale por caracteres entre la
a
y lad
o números entre 6 y 9 - [:alnum:], [:alpha:], etc. (ver manual de grep) corresponden a conjuntos particulares de caracteres
Anclas: comienzo o fin de una línea:
- ^ y $ corresponden al comienzo y fin de una línea
grep -i if if.txt grep -i "^if" if.txt
Repetición: metacaracteres que se aplican a una regex que le antecede
- ? regex aparece cero o a lo sumo una vez
- * regex aparece cero o más veces
- + regex aparece 1 o más veces
- {n} regex aparece exactamente
n
veces - {,m} regex aparece a lo sumo
m
veces - {n,m} regex aparece entre
n
ym
veces
Concatenación: las regex se pueden concatenar y valen por la unión de ambas regex
grep "[iI][fF]" if.txt
Alternación: usando | es posible especificar regex alternativas (equivale al operador lógico OR).
egrep "IF|life" if.txt egrep "I[fF]|life" if.txt
Precedencia: repetición > concatenación > alternación. La precedencia se puede cambiar usando paréntesis ( )
para agrupar sub-expresiones regulares.
Expresiones regulares básicas vs. extendidas: en modo básico (por defecto), los metacaracteres ?, +, {, |, ( y ) no funcionan, deben usarse precedidos por \. Es preferible siempre usar la grep -E o egrep
Ejemplo más complejo: extraer emails de un mailbox
Si quiero extraer líneas con direcciones de email:
grep -E "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" mbox
Si sólo quiero las direcciones de email, uso la opción '-o':
grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" mbox
Ejemplo: extraer número IP de un mailbox
grep -E -o "([0-9]{1,3}[\.]){3}[0-9]{1,3}" mbox
Ejemplo de PES (Potential Energy Surface):
cálculo de HF: hf.out
Extraigo las distancias:
grep "^ ! R1 " hf.out|grep "DE/DX"|cut -b 22-25 >nada1
Otra forma de hacer esto:
grep '^ !.*DE/DX' hf.out|tr -s " " "\t"|cut -f4
Extraigo las energías:
grep '^ SCF Done: ' hf.out|cut -b 26-35 >nada2
Junto ambas columnas:
paste nada1 nada2
Finalmente procesamos los datos con pyxplot para generar la curva de PES
SED: Stream Editor
sed es un descendiente directo de ed, sólo que en lugar de trabajar interactivamente con el editor, sed ejecuta uno o más comandos de ed en un stream de bytes que recibe por stdin
o desde un archivo, volcando a stdout
el resultado. Básicamente todo lo que se puede hacer en ed se puede hacer con sed.
Ejemplos:
sed -nr '/if/p' if.txt sed -nr '/[iI][fF]/p' if.txt sed -nr '/^[iI][fF]/p' if.txt sed -rn 's/If/IF/' if.txt sed -rn 's/If/IF/p' if.txt sed -r 's/^I[fF]/SI/' if.txt sed -r 's/^ *$/ --------/' if.txt
Volvemos al ejemplo del HF: en el ejemplo que vimos usamos cut para extraer las columnas 26 a 35
grep '^ SCF Done: ' hf.out | cut -b 26-35
pero si sustituimos los espacios en blanco por tabuladores, entonces podemos usar cut haciendo referencia al campo (-f):
grep '^ SCF Done: ' hf.out | sed 's/^ //; s/ */\t/g' | cut -f5
Ojo con los metacaracteres: a veces debo usar regex extendido:
grep '^ SCF Done: ' hf.out | sed -r 's/^ //; s/ +/\t/g' | cut -f5