Linux / Comando / grep: buscar texto y expresiones regulares

grep es un comando que busca líneas que coincidan con un patrón especificado en archivos o en la salida de comandos. Además de la búsqueda básica, admite ignorar mayúsculas y minúsculas, seleccionar líneas que no coincidan, búsqueda recursiva en directorios, expresiones regulares y mostrar contexto antes y después.

La forma más básica es grep 'PATRÓN' ARCHIVO. Dado que el patrón puede contener caracteres con un significado especial en el shell, es más seguro acostumbrarse a encerrarlo entre comillas simples.

¿Qué es el comando grep?

grep lee la entrada línea por línea y muestra las líneas que coinciden con el patrón. Su nombre proviene del comando g/re/p de ed, un editor de texto de Unix, que significa buscar y mostrar expresiones regulares en todo el alcance.

Sin archivos y sin recursión, grep lee la entrada estándar, por lo que puede recibir una canalización. Con recursión y sin operando de archivo, GNU grep busca en el directorio actual. El modo predeterminado interpreta expresiones regulares básicas (BRE); -E selecciona expresiones regulares extendidas (ERE).

Sintaxis básica y primera búsqueda

La sintaxis básica es la siguiente. Los corchetes indican opciones y no se deben ingresar en el comando real.

grep [OPCIONES] 'PATRÓN' [ARCHIVO...]

Para buscar líneas que contengan ERROR en app.log, ejecute lo siguiente.

grep 'ERROR' app.log

Si se especifican varios archivos, el nombre de cada archivo aparecerá junto con cada resultado.

grep 'ERROR' app.log worker.log

También se puede buscar en la entrada estándar. El siguiente comando muestra, sin distinguir entre mayúsculas y minúsculas, las líneas de los mensajes del kernel que contienen usb.

dmesg | grep -i 'usb'

Opciones de grep de uso frecuente

Opciones Función Ejemplo de uso
-i Buscar sin distinguir mayúsculas y minúsculas grep -i 'error' app.log
-v Seleccionar líneas que no coincidan grep -v '^#' config
-n Mostrar números de línea en los resultados grep -n 'TODO' main.c
-w Buscar el patrón como palabra completa grep -w 'cat' words.txt
-x Seleccionar cuando toda la línea coincida con el patrón grep -x 'enabled' status.txt
-F Tratar el patrón como una cadena literal, no como una expresión regular grep -F 'a.b' data.txt
-E Usar expresiones regulares extendidas grep -E 'error|failed' app.log
-r Buscar recursivamente en subdirectorios grep -r 'listen' /etc/nginx
-l Mostrar solo los nombres de archivos que coincidan grep -rl 'deprecated' src
-c Mostrar el número de líneas coincidentes por archivo grep -c 'ERROR' app.log
-A, -B, -C Mostrar el contexto anterior, posterior o ambos de las líneas coincidentes grep -C 2 'panic' app.log

Estas opciones pueden combinarse. Por ejemplo, grep -in 'error' app.log realiza la búsqueda ignorando mayúsculas y minúsculas mientras también muestra los números de línea. Puede consultar el comportamiento detallado y las opciones extendidas de GNU en el manual oficial de GNU Grep.

Distinguir entre cadenas de texto y expresiones regulares

Buscar cadenas literales con -F

Para encontrar caracteres que tienen un significado especial en expresiones regulares, como el punto, el asterisco o los corchetes, tal como son, -F es conveniente. En el siguiente comando, el punto se trata como un punto literal, no como cualquier carácter.

grep -F '192.168.0.1' access.log

-F busca la cadena literalmente, pero no exige que sea una palabra o una línea completa. Por ejemplo, la dirección del ejemplo también podría aparecer como prefijo de una cadena más larga. Añada -x si toda la línea debe coincidir o defina los límites adecuados al formato de sus datos.

Usar expresiones regulares extendidas con -E

Usando -E, se puede utilizar la sintaxis de expresiones regulares extendidas, como |, +, ?, incluyendo paréntesis, de una manera más legible. El siguiente ejemplo busca líneas que contengan uno de ERROR, WARN o FATAL.

grep -E 'ERROR|WARN|FATAL' app.log

En GNU grep, la diferencia principal entre expresiones regulares básicas y extendidas radica en la notación. Si la compatibilidad con otros entornos es importante, verifique la implementación y las opciones de soporte de grep en el sistema objetivo.

Especificar el inicio y el fin de la línea

El acento circunflejo (^) indica el inicio de una línea y el signo de dólar ($), el final. Para encontrar líneas vacías, use ^$, sin ningún carácter entre ambos límites.

grep '^server' config.txt
grep 'completed$' job.log
grep '^$' notes.txt

Para excluir las filas vacías y las filas de comentarios en el archivo de configuración, puede aplicar las dos condiciones en orden de la siguiente manera.

grep -v '^[[:space:]]*#' app.conf | grep -v '^[[:space:]]*$'

Reducir con precisión el alcance de la búsqueda

Coincidencia de palabra completa y línea completa

-w selecciona filas donde el patrón coincide con toda la palabra. Por ejemplo, grep -w 'cat' encuentra cat, pero generalmente no selecciona cat dentro de category.

grep -w 'root' /etc/passwd

-x solo selecciona cuando toda la fila coincide exactamente con el patrón.

grep -x 'active' service-status.txt

Buscar filas que no coinciden

-v invierte la selección. El siguiente ejemplo solo imprime las filas que no contienen DEBUG.

grep -v 'DEBUG' app.log

Se puede excluir sin importar mayúsculas o minúsculas combinando con -i.

grep -iv 'debug' app.log

Buscar múltiples patrones a la vez

Si se usa -e varias veces, se puede especificar cada patrón por separado. No es necesario combinarlos en una expresión regular compleja, lo que hace que sea fácil de leer en un script.

grep -e 'ERROR' -e 'FATAL' app.log

Si hay muchos patrones, se puede crear un archivo con uno por línea y leerlo con -f.

grep -f patterns.txt app.log

Buscar recursivamente en todo un directorio

Diferencia entre -r y -R

-r busca recursivamente archivos en los directorios especificados. Sigue enlaces simbólicos especificados directamente en la línea de comandos, pero omite los enlaces simbólicos encontrados durante la búsqueda recursiva.

grep -rn 'database_url' ./config

-R de GNU grep sigue incluso los enlaces simbólicos encontrados durante la búsqueda recursiva. Se debe usar solo cuando la intención sea clara, ya que puede crear enlaces circulares o un alcance de búsqueda mayor al esperado.

Incluir o excluir formatos de archivo

--include busca solo los nombres de archivo que coinciden con el patrón especificado, y --exclude omite los archivos que coinciden. Se colocan comillas alrededor del patrón para que el shell no expanda primero el asterisco.

grep -rn --include='*.conf' 'timeout' /etc
grep -rn --exclude='*.min.js' 'deprecated' ./src

Para excluir un directorio específico, use --exclude-dir.

grep -rn --exclude-dir='.git' --exclude-dir='node_modules' 'api_key' .

Comprobar solo los nombres de archivo que coincidan

Si necesita una lista de archivos más que el contenido coincidente, use -l. Cada archivo deja de buscar una vez que se encuentra la primera coincidencia, por lo que es adecuado para su propósito.

grep -rl --include='*.html' 'jb-heading' .

Por el contrario, para encontrar solo los archivos que no coinciden con el patrón, use -L en mayúscula.

grep -rL --include='*.html' 'jb-heading' .

Imprimir los resultados de manera legible

Mostrar número de línea y nombre de archivo

-n muestra el número de la línea coincidente. En GNU grep, use -H para mostrar el nombre incluso al buscar en un solo archivo, o -h para ocultarlo.

grep -nH 'listen' nginx.conf

Ver el contexto antes y después de la fila coincidente

Si es difícil determinar la causa solo con las filas de errores, vea las filas circundantes con -A, -B y -C. Los números indican la cantidad adicional de filas que se mostrarán.

grep -A 3 'ERROR' app.log
grep -B 2 'ERROR' app.log
grep -C 2 'ERROR' app.log

-A 3 agrega 3 filas posteriores, -B 2 agrega 2 filas anteriores, y -C 2 agrega 2 filas antes y después.

Imprimir solo la parte coincidente

-o imprime solo la parte que coincide con el patrón, no la fila completa. Si hay varias coincidencias en una sola fila, se muestran como salidas separadas.

grep -oE '[0-9]{3}-[0-9]{4}' contacts.txt

Para resaltar la parte coincidente en la terminal, se puede usar --color=auto. Cuando se redirige la salida a un archivo u otro comando, use auto o never para evitar que los caracteres de control de color se mezclen.

Uso en logs y salidas de comandos

Buscar errores en registros recientes

Para buscar solo en un rango reciente en lugar del registro completo, conéctelo con tail.

tail -n 500 app.log | grep -iE 'error|failed|fatal'

Para continuar filtrando nuevos registros que se agregan al archivo, puede usarlo de la siguiente manera.

tail -F app.log | grep --line-buffered 'ERROR'

--line-buffered es una opción de extensión GNU y vacía el búfer de salida cada vez que llega una línea para reducir la demora en la canalización. Puede ver métodos de seguimiento que incluyen rotación de registros en Cómo usar el comando tail en Linux.

Filtrar resultados de servicios y procesos

Puede encontrar un nombre de servicio específico en la salida de systemctl.

systemctl list-unit-files | grep 'nginx'

Si el objetivo es solo verificar la existencia de procesos, pgrep a menudo es más directo que ps | grep. Para buscar el nombre del comando junto con sus argumentos, puede ejecutarlo de la siguiente manera.

pgrep -af 'nginx'

Contar el número de filas coincidentes

-c imprime el número de filas que coinciden, no el número de coincidencias. Aunque un patrón aparezca varias veces en una fila, esa fila solo se cuenta una vez.

grep -c 'ERROR' app.log

Para contar todas las coincidencias dentro de una fila, se puede separar cada coincidencia con -o y luego contarlas con wc -l.

grep -o 'ERROR' app.log | wc -l

Verificar solo la existencia sin salida

-q omite la salida normal y permite comprobar si aparece un patrón. Prepare status.log en una carpeta de prueba; el siguiente if solo anuncia una coincidencia. Sin else no distingue ausencia de coincidencias de un error, ni garantiza que el script termine con fallo. Si esa distinción importa, capture inmediatamente el estado de grep y trate 1 y 2 por separado.

if grep -q 'ready' status.log; then
  echo 'Servicio preparado'
fi

Entendiendo el estado de salida de grep

grep devuelve los resultados de búsqueda tanto como cadena de resultado como estado de salida. Generalmente, devuelve 0 si hay filas coincidentes, 1 si no hay filas coincidentes, y 2 si no se puede leer el archivo o hay errores de sintaxis.

Estado de salida Significado Decisión en scripts
0 Hay una o más coincidencias Procesar como si la condición fuera verdadera
1 No hay coincidencias Podría ser un resultado de búsqueda normal
2 Ocurrió un error Verifique el archivo de entrada, los permisos o el patrón

Por lo tanto, no se debe asumir que la ejecución del comando falló solo por no haber resultados. En la automatización, es necesario distinguir entre 1 y el verdadero error 2. El GNU grep -q puede terminar con el estado 0 incluso si se encuentran otros errores, por lo que si es importante detectar errores en todos los archivos de entrada, se necesita una verificación adicional.

Problemas comunes y soluciones

Cuando el patrón comienza con un guion

Patrones como -ERROR pueden confundirse con opciones. Se coloca el patrón después de --, que indica el final de las opciones.

grep -- '-ERROR' app.log

Cuando aparece el mensaje Binary file matches

Si GNU grep determina que la entrada es un archivo binario, puede mostrar solo el mensaje en lugar de la línea coincidente. Si está seguro de que en realidad es un archivo de texto, puede tratarlo como texto usando -a.

grep -a 'ERROR' mixed-data.log

Por el contrario, para excluir archivos binarios durante una búsqueda recursiva, se puede usar -I. No use -a con datos binarios desconocidos sin precaución, ya que podrían contener caracteres de control que dañen el terminal.

Cuando los resultados difieren debido a caracteres especiales de expresiones regulares

El punto coincide con cualquier carácter en expresiones regulares, y el asterisco indica repeticiones del patrón anterior. Si solo estaba buscando una cadena simple, use -F; si estaba usando expresiones regulares, coloque todo el patrón entre comillas simples para evitar la expansión del shell.

Cuando la búsqueda recursiva es demasiado lenta o produce muchos resultados

Restringa el directorio de inicio de búsqueda y excluya archivos innecesarios como --include, --exclude, --exclude-dir. Si descarta todo el error estándar solo para ocultar errores de permiso, podría pasar por alto problemas importantes, por lo que es mejor primero verificar el alcance de la búsqueda y los permisos de los archivos.

Preguntas frecuentes

grep, ¿distingue entre mayúsculas y minúsculas por defecto?

Sí. La búsqueda predeterminada distingue entre mayúsculas y minúsculas. Si no desea que distinga, use -i. También debe considerar que los resultados del manejo de mayúsculas y minúsculas pueden variar según la configuración regional.

grep -r y grep -R, ¿en qué se diferencian?

En GNU grep, ambos realizan búsquedas recursivas, pero -R sigue todos los enlaces simbólicos que encuentra durante la búsqueda. Para la búsqueda habitual de archivos fuente o de configuración, -r es más predecible.

Si no hay resultados de búsqueda, ¿es un error?

No necesariamente es un error. Si no hay coincidencias, normalmente devuelve el estado de salida 1, y errores como fallos de acceso al archivo u opciones incorrectas se distinguen con el estado 2.

¿Cómo encontrar líneas que contengan cualquiera de varios términos de búsqueda?

Puede usar el operador de selección de expresiones regulares extendidas como grep -E 'error|warning' ARCHIVO, o repetir -e como grep -e 'error' -e 'warning' ARCHIVO. Para tratar la palabra clave como una cadena literal en lugar de una expresión regular, también puede usar -F.

Resumen

Es útil familiarizarse con la búsqueda de cadenas comunes usando grep -F, varias condiciones de expresiones regulares con grep -E y la búsqueda en todo el directorio con grep -r. Para facilitar la interpretación de los resultados, puede usar -n y -C; si solo necesita la lista de archivos, -l; y si solo desea verificar la existencia en un script, puede usar -q.

Es importante rodear el patrón con comillas simples, limitar específicamente el alcance de la búsqueda recursiva y distinguir entre el estado de finalización 1 y el estado de error 2 para un uso seguro. Para revisar otras herramientas básicas, consulte Lista de comandos frecuentes en Linux.