Grep

De castillowiki
Saltar a: navegación, buscar

Grep es uno de los comandos más útiles de cualquier SO tipo Unix. Permite imprimir las líneas que concuerdan con un patrón. Gracias a Grep y a las | tuberías se pueden hacer muchas cosas en la terminal de Linux.

En realidad, la parte más interesante del grep son las expresiones regulares, lo cual necesita un manual para ellas solas.

Primeras expresiones regulares

Grep acepta expresiones regulares muy potentes, egrep aún más. Se puede hacer que grep se comporte como egrep con -E.

En este enlace se pueden ver las diferencias entre lenguajes en las expresiones regulares. [1]

Para estas expresiones regulares utiliza unos caracteres especiales:

  • . Significa cualquier carácter.
  • * Significa que el carácter anterior se repite 0 o indefinidas veces. Si ponemos a* decimos que la a puede o no estar o estar n veces. Con ese mismo razonamiento, podemos poner .* para indicar que cualquier carácter se repite un número indefinido de veces o ninguna.
  •  ? Significa que el anterior carácter está una o 0 veces. a\? indica que la a está 1 o ninguna vez. .\? indica que hay uno o ningún caracter. No pueden haber 2. el \ indica que no debe interpretar el ? como tal, sino como un carácter especial, con egrep no se debe poner el \.
  • + Significa que el anterior está por lo menos una vez. con grep se pone con \ y con egrep no.
  • () Sirve para poner una expresión regular dentro y alternarlas con | que es la o lógica.
  • {n}, {n,}, {n,m} Sirven para decir que la expresión anterior se puede repetir n, n o más veces y entre n y m veces, respectivamente.
  • ^ Signifca el principio de la línea. También significa negación si se pone dentro de []. Se puede usar como [^a], por ejemplo, para negar el carácter a.
  • $ El final de la línea
  • [] Sirve para poner dentro caracteres y decir que pueden ser uno de ellos. [abc], por ejemplo, indica que hay una a, una b o una c, no las tres juntas. Se pueden poner intervalos [a-z] para las minúsculas o [a-Z] Para todas las letras. [a-Z0-9] para letras y números... Si dentro ponemos ^a, por ejemplo, indicamos que esa letra no puede estar.
  • \< \> significan el principio y el final de una palabra.
  • \w Un alfanumérico.

Así, este comando:

   $ grep '^b.*a.*$' fichero

Saca las líneas que empiezan con b, tienen al menos una a, entre dos grupos de las letras que sean hasta el final de la línea.

Este:

   $ grep 'ba\+'

Muestra las líneas que tienen la cadena ba, baa, baaa ...

El caso de las direcciones IP

Este otro:

   $ egrep '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' fichero

Busca direcciones IP. Observa que el \. sirve para decirle que el punto ha ser literal, no cualquier caracter. el {1,3} obliga a que el número se repita al menos una vez y no más de 3. Pero esto se puede optimizar, ya que podemos repetir el patron.

   $ egrep '([0-9]{1,3}\.){3}[0-9]{1,3}' fichero

Incluso, si sabemos que luego ha de ir un espacio, podemos usar este:

   $ egrep '([0-9]{1,3}[\. ]){4}'

Es decir, después de los 3 números va un espacio o un punto.

Pero esto detectaría direcciones como esta: 0.999.010.999, que no es una IP. Podemos mejorarlo forzando a que ningún número sea mayor que 299:

   $ egrep '([12]?[0-9]{1,2}[\. ]){4}'

Si seguimos mejorando, podemos evitar que sea mayor que 259 con:

   $ egrep '((1?[0-9]{1,2}[\. ])|(2[0-5][0-9][\. ])){4}'

Si empieza por 1 o tiene menos de 3 números cumplirá el patrón de delante y si empieza por 2 y tiene dos números más, el segundo patrón. Como se ve, no deja que el segundo número sea mayor que 5. Siguiente mejora:

   $ egrep '((1?[0-9]{1,2}[\. ])|(2[0-4][0-9][\. ])|(25[0-5][\. ])){4}'

Ahora si empieza por 25, el segundo número no puede ser más grande que 5. Se puede simplificar quitando algunos paréntesis y poniendo el [\. ] al final.

   $ egrep '((1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])[\. ]){4}'

Le quitamos el [] al punto para poner un ?:

   $ egrep '((1?[0-9]{1,2}|2[0-4][0-9]|25[0-5])\.?){4}'

Se puede probar con este fichero:

hola
123.a
abc.abc.abc.abc
a.b.c
1.2.3.4
1.2.3
192.168.1.1
192.168.1
192.168..1
192.168.a.1
192.168.ñ.1
192.168.10000.2
192.168.900.2
192.168.257.2
192.168.199.2
192.168.255.255
....
...

Opciones de grep

En man grep se pueden ver todas, aquí voy a poner las que considero más útiles.

  • -o saca sólo la parte que coincide con el patrón, no la línea entera.
  • -E evalúa la expresión regular de manera extendida, como el egrep.
  • -e sirve para concatenar expresiones regulares, algo así como la o lógica.
  • -v saca las líneas que NO coinciden con el patrón.
  • -i sirve para ignorar las diferencias entre mayúsculas y minúsculas.
  • -w sirve para seleccionar exactamente la palabra que buscamos, no otras que la contengan. Por ejemplo, si buscas apple, que no salga pineapple ni apples.
  • -c Cuenta las líneas con coincidencias
  • -n Muestra el número de la línea.
  • -h y -H Para ocultar o mostrar el nombre del fichero donde se ha encontrado la coincidencia. -h está por defecto cuando sólo se busca en un fichero.
  • -A Para mostrar las n líneas siguientes a la encontrada. --after-context=NUM
   $ ifconfig | grep -A 2 'eth0'
   # Muestra la línea que ha encontrado y las dos siguientes. Lo siguiente tiene el mismo efecto:
   $ ifconfig | grep -2 'eth0'
  • -B Muestra las dos líneas anteriores al patrón. --before-context=NUM

Buscar múltiples palabras

Se pueden buscar varias palabras con el | que es la o lógica.

   $ grep 'warning|error|critical' /var/log/messages
   # se puede mejorar buscando sólo palabras:
   $ grep -w 'warning|error|critical' /var/log/messages

Buscar ficheros por su contenido

Para buscar por contenido se puede usar grep o find. En el siguiente ejemplo se pueden ver varias opciones, primero se asegura de que va colorear el resultado, luego el -i ignora las mayúsculas o minúsculas, luego el R buscar recursivamente el los subdirectorios, el n saca el número de línea y el H muestra el nombre del fichero donde lo encuentra.

   $ grep --color=auto -iRnH 'main(' *.c
   # Este otro lo hace con find
   $ find . -name "*.c" -print | xargs grep "main("

Enlaces

Explicar expresiones regulares [2]

https://s3-us-west-1.amazonaws.com/gregable/puzzle.html

https://regexcrossword.com/