Aprendemos a usar grep en el aula: guía breve pero fundamental.
grep como legado UNIX puro.
Antes de entrar en opciones y ejemplos, nos vamos a detener tan solo un minuto en lo que representa grep dentro del ecosistema UNIX.
No es solo una herramienta para buscar texto, sino una pieza clave, un importante legado respecto a una idea mucho más grande que el comando en sí... Un concepto inherente a esta orden que debería estar recordándonos permanentemente cómo programar bien.
Dentro del ecosistema UNIX, los programas bien hechos no están pensados para hacerlo todo, sino para hacer una sola cosa bien (principio KISS) y para poder combinarse entre sí. Esta combinación se logra a través de las tuberías (pipes), en las cuales la salida de un comando (o programa), se convierte en la entrada de otro.
grep encarna ese principio de forma excelente, porque no necesita saber de dónde vienen los datos ni qué se hará con ellos después. Simplemente recibe texto, filtra según un criterio y devuelve el resultado. Esta simplicidad es lo que le permite integrarse en flujos más complejos: filtrar el "ruido innecesario" en la salida de otros comandos, analizar archivos de "logs" en tiempo real, procesar listados generados por otros comandos o inspeccionar grandes volúmenes de información sin necesidad de herramientas pesadas.
En este sentido, utilizar grep es empezar a pensar con cabeza UNIXera, en donde construir soluciones a partir de piezas pequeñas encadenadas con absoluta precisión, es... mandatory!
Es una forma de trabajar en la cual la verdadera potencia no radica en un comando o programa individual, sino en la manera en que estos se conectan entre sí.
Prefacio.
grep es una de esas herramientas que aplicada de manera directa en la terminal puede parecer simple, pero que rápidamente se va volviendo indispensable cuando se empieza a trabajar con archivos de "logs" o directamente con código. En esencia, hace algo muy concreto: buscar texto. Sin embargo, la forma en la cual lo hace (tanto como también las opciones que ofrece) son determinantes al utilizarlo como filtro básico o como potente herramienta de diagnóstico.
No me importa cómo esté escrito: grep -i
Una de las primeras dificultades que podemos encontrar, es que el texto no siempre aparece exactamente como lo esperamos... o como lo recordamos.
El mismo puede estar en mayúsculas, en minúsculas, o en una combinación de ambos casos.
Por ejemplo, yo mismo, ayer, creé una función llamada "obtener_noticias_openbsd" y la estaba invocando como "obtener_noticias_OpenBSD"... Resultado: error de ejecución en el flujo esperado del programa.
Es el eterno dilema de escribir las cosas como realmente se debe, por un lado, vs lo que se recomienda en programación, por otro (sumale a eso "año vs anio", "función_principal vs funcion_principal", y así).
Acá es donde entra en juego JuanI Vellozo, quien presentó este ejemplo: el de la opción "-i". Al utilizarla, grep deja de distinguir entre mayúsculas y minúsculas (deja de lado el "case sensitive"), lo cual permite encontrar coincidencias sin la preocupación de cómo fue escrito el texto. Esta es una mejora procedimental que evita muchos "falsos negativos" cuando se están buscando palabras clave o comandos problemáticos dentro del código.
Ejemplo.
Supongamos que existe un archivo llamado "log.txt" con un contenido como este:
[001] Error al iniciar módulo: no se encuentra el archivo o directorio.
[002] OK.
[003] OK.
[004] Conexión no establecida
[005] OK.
[006] OK.
[007] ERROR: módulo de conexión faltante.
[008] Usuario no conectado.
[009] OK.
[010] OK.
[011] Saliendo con código de error 1.
Al hacer
grep -i "error" log.txt
la terminal nos devuolverá tanto "Error", como "ERROR" y "error", resolviendo el problema de las mayúsculas sin tener que "debuguear" demasiado.
Pero... ¿en dónde está el error, exactamente? grep -n
Cuando el archivo crece o se empieza a volver "inmanejable", encontrar una coincidencia ya no es suficiente: también hay que ubicarla.
Gracias a Ramiro Bergara, vimos la demostración de que la opción -n descubre este contexto que en muchas ocasiones es fundamental, mostrando el número de línea junto a cada resultado.
Esto potencia a la utilidad de búsqueda de grep, porque permite saltar directamente al lugar exacto dentro del archivo en donde está el error o lo buscado. En tareas de depuración o edición, ese número deja de ser un simple detalle, pasando a ser una guía importante.
Ejemplo.
grep -n "error" log.txt
El resultado incluirá tanto las líneas como sus números reales, algo así como:
1:[001] Error al iniciar módulo: no se encuentra el archivo o directorio.
7:[007] ERROR: módulo de conexión faltante.
11:[011] Saliendo con código de error 1.
Esto permite ubicar rápidamente al problema.
¿Voy a tener que hacer esto en cada uno de mis programas? grep -r
Hay un gran salto que es posible dar cuando no estamos obligados a parametrar nuestras búsquedas dentro de un solo archivo. En el caso de un programador que posee una cantidad de programas en su haber, la información, lógicamente, está distribuida en múltiples archivos y directorios. Thiago González mostró que grep puede recorrer directorios y archivos enteros de manera recursiva, buscando en todo lo que a su paso encuentra. Esto hace que la necesidad de tener que saber de antemano en dónde está lo que buscamos, sea algo totalmente irrelevante, ya que en lugar de ir abriendo todos los archivos uno por uno y aplicando herramientas de búsqueda en cada uno de ellos, se delega la totalidad de dicha tarea a este comando, el cual lo hará de manera inmediata y efectiva.
Ejemplo.
Este es un volcado real de mi directorio de scripts local, el cual busca la ocurrencia "set -e" en "$PWD", s decir "en el lugar en donde esté 'parada' la terminal en ese momento".
grep -r "set -e" $PWD
/mnt/HDD_4TB/datos_linux/01_Entropía/CodeBerg/_GeneBerg/_respaldos/geneberg.sh:set -euo pipefail
/mnt/HDD_4TB/datos_linux/01_Entropía/CodeBerg/_GeneBerg/geneberg.sh:set -euo pipefail
/mnt/HDD_4TB/datos_linux/01_Entropía/CodeBerg/KDEnTux/KDEnTux.sh:set -e # Detención script inmediatamente si algún comando falla.
/mnt/HDD_4TB/datos_linux/01_Entropía/CodeBerg/KDEnTux/KDEnTux.sh: # Se utiliza "vainfo" para listar puntos de entrada VA-API. Si falla, KDEnTux se detendrá gracias al "set -e" del inicio.
/mnt/HDD_4TB/datos_linux/01_Entropía/CodeBerg/GeneRead/generead.sh:set -euo pipefail
/mnt/HDD_4TB/datos_linux/01_Entropía/CodeBerg/IA_local/instalador_ia_local.sh:set -euo pipefail
Pero... yo quiero ver "todo lo otro", no "eso"... grep -v
A este atributo de grep, creo que lo charlamos entre todos, y tiene que ver con otra situación frecuente, que es la de no siempre necesitar ver lo que coincide, sino lo inverso.
Me explico mejor: a veces lo que interesa es limpiar un archivo, eliminar líneas irrelevantes o quedarse con lo que no cumple con cierta condición.
Para eso existe "-v", que invierte el criterio de búsqueda: en lugar de mostrar coincidencias, muestra todo lo demás, es decir, todo lo que NO coincide con lo que le estemos indicando.
Esto es especialmente útil al ponernos a trabajar con archivos de configuración o de registros en donde el filtrado de "ruido" es imprescindible (comentarios, líneas repetitivas, etc).
Ejemplo.
Dado un archivo de configuración con comentarios:
# Configuración del sistema
usuario=admin
# Contraseña
password_SHA-256=p989e5ap9h7t6894d4topja34l5l69xq
Podemos quitar los comentarios con:
grep -v "^#" config.conf
El resultado será solo las líneas útiles, sin las que empiezan con #:
usuario=admin
password_SHA-256=p989e5ap9h7t6894d4topja34l5l69xq
Un dato "de color": grep --color=auto
Por último, está el aspecto visual, que muchas veces se subestima. Cuando se trabaja con grandes volúmenes de texto, encontrar rápidamente coincidencias dentro de cada línea puede ser más dificultoso de lo que parece, y más cuando llevamos mirando el mismo código durante horas.
La opción --color=auto resuelve esto resaltando las coincidencias directamente en la salida. No cambia el resultado en sí, pero sí la forma en que lo percibimos, haciendo que la lectura sea más inmediata y menos propensa a errores.
Ejemplo.
Volvamos al caso del ejemplo en grep -r.
Era este: grep -r "set -e" $PWD
Pero supongamos que queremos resaltar visualmente a las ocurrencias encontradas, no solamente volcarlas en pantalla.
En ese caso, podemos simplemente intercalar la opción correspondiente en la misma línea, de esta manera:
grep --color=auto -r "set -e" $PWD
El resultado, será el mismo que el mostrado en la imagen de este artículo.
P.D.: para que no te rompas la cabeza intentándolo... Porque te estoy leyendo el pensamiento y ya sé que vas a querer hacer lo mismo que yo intenté en algún momento ("color=1", "color1", etc...), y te quiero ahorrar tiempo y enseñarte algo más...
- "--color" no acepta colores, solo acepta "auto", "always" y "never" (el cual ya viene por omisión y no es necesario, en principio).
- "color=auto", colorea solo si detecta que la salida va a una terminal o pantalla, pero si detecta que la salida es redirigida a un archivo, deja de resaltar con color automáticamente.
Este modo se vuelve útil en casos específicos, por ejemplo cuando querés forzar colorido a través de una tubería hacia otro comando o programa que sí sepa interpretar código ANSI, el cual es, en definitiva, el código generado por grep cuando está en modo "color=always".
- "color=always" se comporta de manera literal: inserta comandos de color aunque eso pueda llegar a ensuciar su salida.
Epílogo.
grep posee muchas opciones, y de hecho te invito a que las investigues por tu cuenta, pero éstas, utilizadas de manera combinada (tal como nos enseña UNIX), transforman a cualquier comando (en este caso, a grep) en algo más que una simple orden o un simple buscador de texto: permiten explorar archivos, localizar problemas y filtrar información con precisión.
Esta guía fue escrita para mis estudiantes y para los lectores que la aprovechen, pero también para mí mismo, porque al bajar a tierra escribiendo lo que uno aprendió, lo "hace carne".
Para alguien que esté empezando a utilizar este comando, la moraleja es que no es tan importante tratar de memorizar todas las posibilidades como entender que cada una de estas variantes responde a una necesidad concreta que irá apareciendo naturalmente al trabajar con datos reales en BASH.

0 Comentarios:
Publicar un comentario