Linux: Buscar archivos que contengan texto

Este tema es un conocimiento esencial para todos los usuarios de UNIX, Linux, Solaris, OS X y BSD. Además, la certificación LPI contiene preguntas engañosas sobre esto...

Este tema es un conocimiento esencial para todos los usuarios de UNIX, Linux, Solaris, OS X y BSD. Además, la certificación LPI contiene preguntas engañosas al respecto.

Si desea buscar archivos con un nombre de archivo determinado mediante la línea de comandos, utilice los comandos buscar o localizar. Pero si desea encontrar archivos que contengan cierto texto, querrá usar grep y sus amigos. Aquí, el término amigos se refiere a un grupo de herramientas similares que se adaptan a un formato de datos o estructura de archivo específicos, como texto sin formato, archivos comprimidos y documentos PDF.

Búsqueda básica de texto

El nombre grep es una combinación de las letras iniciales de las cuatro palabras "global / regular expression / print". Esto es similar a formular patrones de búsqueda en el editor de secuencias sed. grep está diseñado para encontrar patrones acordes en flujos de datos completos (archivos). Los patrones dados se interpretan como texto o Expresiones regulares (vea un ejemplo a continuación).

Ejemplo 1 muestra cómo descubrir todas las apariciones del nombre de marca "Mikrotik" escrito como "Mikrotik" o "MikroTik". Usamos grep para buscar en todos los archivos cuyo nombre comience con "factura-2017". El resultado es una lista de nombres de archivo con las coincidencias correspondientes, una por línea precedida por el nombre del archivo.

Ejemplo 1: Llamar a grep con una expresión regular

1
2
3
$ grep Mikro[tT]ik invoice-2017*
invoice-20170015.text:Mikrotik Routerboard 750GL Gigabit Switch
invoice-20170045.text:MikroTik RouterBoard RB250GS Gigabit Switch

Esta salida es útil pero no contiene el número de línea. Para mostrar el número de línea con grep, use la opción -n o --line-number como versión larga. Entonces, el resultado es el siguiente:

Ejemplo 2: llamar a grep con una expresión regular y números de línea

1
2
3
$ grep -n Mikro[tT]ik invoice-2017*
invoice-20170015.text:64:Mikrotik Routerboard 750GL Gigabit Switch
invoice-20170045.text:65:MikroTik RouterBoard RB250GS Gigabit Switch

En cada línea, los campos de salida individuales están separados por dos puntos. El primer campo contiene el nombre del archivo ("factura-20170015.text"), el segundo campo es el número de línea dentro del archivo coincidente ("64") y el tercer campo es la línea completa con el texto coincidente ( "Conmutador Gigabit Mikrotik Routerboard 750GL").

Más opciones de grep

grep tiene una larga lista de opciones útiles. Consulte la página del manual para obtener una descripción detallada. Los más relevantes para este artículo son:

Opción corta Opción larga Descripción


-i --ignore-case escritura en mayúsculas y minúsculas -l --files-with-matches se detiene después de la primera coincidencia y genera el nombre del archivo -n --line-number muestra el número de línea de la coincidencia -r --búsqueda recursiva recursivamente --color or --colour highlight the actual match

Con la excepción de resaltar la coincidencia real, Ejemplo 3 combina las opciones -i, -r y -l como se describe arriba. Esto simplifica la llamada y devuelve una lista de archivos con coincidencias, sin importar cuántas coincidencias existan para cada archivo. Con la ayuda de esto, puede ver si hay coincidencias y, de ser así, en qué archivos.

Ejemplo 3: cómo buscar todos los archivos que contengan el término "mikrotik" en cualquier forma recursiva

1
2
3
$ grep -irl mikrotik invoice-2017*
invoice-20170015.text
invoice-20170045.text

El comando grep viene con dos variantes especiales: fgrep y egrep. fgrep interpreta el patrón de búsqueda como una cadena de caracteres individuales y es exactamente lo mismo que grep -F (y grep --fixed-strings).

Por el contrario, egrep toma el patrón como una expresión regular y es similar a grep -E (y grep --extended-regexp). En versiones anteriores de Linux anteriores a Debian 4 Etch, ambos comandos se implementan como scripts de shell que llaman a grep con opciones especiales. Hoy en día, las versiones actuales de Linux mantienen los comandos como archivos binarios. En cualquier caso, la búsqueda es un poco más rápida que usar grep sin esta opción especial.

Búsqueda de archivos comprimidos

grep no puede inspeccionar correctamente los archivos comprimidos. Ahora, los especialistas llamados zgrep, bzgrep, xzgrep y zipgrep entran en escena. Estas herramientas lo ayudan a simplificar comandos como este:

1
$ zcat archive.gz | fgrep [pattern]

zcat descomprime el archivo dado y envía su contenido a stdout. Conectado a fgrep, se busca en el flujo de datos el [patrón] dado.

Con la ayuda de los comandos anteriores, no es necesario que descomprima los archivos comprimidos con gzip, bzip2, xz y zip antes de realizar la búsqueda; este paso ocurre entre bastidores. Al igual que con grep, existen las variantes especiales zfgrep y zegrep para gzip, así como bzfgrep y bzegrep para bz, y xzfgrep y xzegrep para xz. Ejemplo 4 muestra cómo buscar un archivo comprimido xz.

Ejemplo 4: Búsqueda de un archivo comprimido xz

1
2
$ xzfgrep Mikrotik invoice-20130015.text.xz
Mikrotik Routerboard RB450G Level 5 680MHz

La búsqueda de archivos comprimidos es un poco más compleja y requiere un poco de secuencias de comandos de shell. Listado 1 demuestra un script de shell que funciona solo con archivos comprimidos gzip. Para simplificar, guardamos el siguiente script con el nombre "search.sh". El script requiere dos parámetros: el patrón de búsqueda y el nombre de archivo del archivo comprimido (ver Ejemplo 5 a continuación).

Listado 1: Búsqueda de archivos gzip comprimidos

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#!/bin/bash

pattern=$1
archive=$2

for filename in $(tar -tzf "$archive");
  do
    match=$(tar -xOzf "$archive" "$filename" | fgrep "$pattern") && echo "$filename:";
    echo "$match" | fgrep --color "$pattern";
    echo "";
  done

Ejemplo 5: Llamar al script

1
2
3
4
5
6
$ ./search.sh Mikro archive.tar.gz
invoice-20110045.text:
Mikrotik

invoice-20110110.text:
MikroTik

Comprender el guión puede necesitar un momento de tiempo. Primero, el script extrae la lista de archivos del archivo y evalúa cada archivo uno tras otro. El bucle exterior for hace todo el trabajo complejo. En segundo lugar, las coincidencias individuales se guardan en la variable $match. Por lo tanto, el archivo actual se extrae del archivo comprimido y luego se canaliza a fgrep. fgrep busca en el flujo de datos e indica una coincidencia con un valor de retorno positivo. En ese caso, se ejecuta el siguiente comando echo y el nombre del archivo se envía a stdout. En tercer lugar, también se imprime la coincidencia real, seguida de una línea vacía. Esto separa las diferentes coincidencias en archivos.

Una alternativa es la herramienta deepgrep que forma parte del motor de búsqueda de escritorio Estrigi (paquete Debian strigi-utils). Busca archivos tar.gz, así como archivos zip, paquetes Debian e incluso archivos de Microsoft Word. Ejemplo 6 muestra cómo funciona. Línea por línea, verá el nombre del archivo y las coincidencias correspondientes.

Ejemplo 6: Buscar un archivo usando deepgrep

1
2
3
4
$ deepgrep Mikro archive.tar.gz
archive.tar.gz/invoice-20110045.text:Mikrotik
archive.tar.gz/invoice-20110110.text:MikroTik
$

Búsqueda de otros tipos de documentos

deepgrep cubre muchos formatos de archivo pero tiene bastantes dependencias de paquetes. En su lugar, puede echar un vistazo a pdfgrep y ssgrep, en su lugar. pdfgrep está especializado para documentos PDF y ssgrep es para hojas de cálculo.

Lo que me gusta de pdfgrep es tanto su simplicidad de uso como su variedad en términos de opciones. Las coincidencias se resaltan sin necesidad de especificar más argumentos.

La opción -n, que se muestra en uso a continuación, ayuda a identificar la página en la que se descubrió el patrón. En el Ejemplo 7, cada línea consta de tres campos de datos separados por una columna: el nombre del archivo, el número de página de la coincidencia y el texto extraído de la coincidencia. Si el terminal de salida admite colores, los campos de datos y las coincidencias se resaltan de diferentes maneras.

Ejemplo 7: Búsqueda de documentos PDF

1
2
3
$ pdfgrep -n Mikro[tT]ik invoice*.pdf
invoice-20120033.pdf:2:MikroTik Sextant 5HnD 18dbi MIMO
invoice-20120075.pdf:1:MikroTik RouterBOARD 250GS Giga

Como se mencionó anteriormente, ssgrep lo ayuda a buscar hojas de cálculo. ssgrep abrevia "spreadsheet grep", y es parte de la herramienta gnumérico. Como formato de archivo, tanto Open/Libre Office Calc como Gnumeric utilizan XML comprimido gzip como formato de archivo. Las versiones más recientes de Microsoft Excel también podrían funcionar, pero no probé. La Figura 1 muestra una hoja de cálculo de ejemplo con datos de ventas y cuatro pedidos.

Gnumeric spreadsheet{.img-responsive}

_Figura 1: Hoja de cálculo de ejemplo de Gnumeric_

Para identificar las celdas individuales que contienen el término "NanoStation", se llama a ssgrep con las opciones -H y -n. -H genera el nombre del archivo como el primer campo de datos, y -n agrega la ubicación: el nombre de la hoja de cálculo y la posición de la tabla. Consulte el Ejemplo 8 a continuación para ver el resultado.

Ejemplo 8:

1
2
3
4
$ ssgrep -Hn "Nano[Ss]tation" orders.gnumeric
orders.gnumeric:orders!C3:5x NanoStation M5
orders.gnumeric:orders!C5:4x NanoStation M2
orders.gnumeric:orders!C6:3x NanoStation M3

Las herramientas presentadas hasta ahora son herramientas de línea de comandos. Para buscar documentos de Open/Libre Office puede usar la herramienta gráfica llamada "loook" (paquete de Debian loook). La Figura 2 muestra la sencilla interfaz gráfica de usuario.

Loook document search{.img-responsive}

_Figura 2: La interfaz gráfica de look_

Conclusión

La búsqueda de formatos de datos es compleja y puede ser una historia interminable. Varias herramientas lo ayudan a identificar fácilmente los archivos relevantes. Para obtener una lista completa de comandos para otros formatos de datos, eche un vistazo a las referencias dadas a continuación.

Lecturas adicionales {#lecturas adicionales}

Agradecimientos

El autor quisiera agradecer a axel beckert y Geroldo Rupprecht por su apoyo y críticas durante la preparación de este artículo.