find y grep resuelven problemas distintos y se complementan. find recorre un árbol de directorios y filtra por los metadatos de cada entrada: nombre, tipo, fecha de modificación, tamaño. grep lee el contenido de los archivos y filtra por un patrón de texto o una expresión regular. Ninguno reemplaza al otro: find no mira qué hay escrito adentro de un archivo, y grep no filtra por fecha ni por tamaño. La potencia real aparece al combinarlos con una tubería, del tipo find ... -print0 | xargs -0 grep ..., el patrón que evita que un nombre de archivo con espacios rompa todo el proceso.
Ver índice de contenidos
- 01¿Qué diferencia hay entre find y grep?
- 02Cómo buscar archivos con find
- 03Acciones de find: -exec {} \; frente a {} + y -delete
- 04El error más común: espacios, -print0 y xargs -0
- 05Cómo buscar texto con grep
- 06BRE, ERE y PCRE: qué cambia de verdad
- 07Combinar find y grep con una tubería
- 08Errores frecuentes
- 09Preguntas frecuentes
- 10Fuentes
¿Qué diferencia hay entre find y grep?
En una terminal —la interfaz de texto donde se escriben comandos, uno por línea— find y grep están entre los comandos que más se usan para ubicar algo entre miles de archivos, y aparecen en cualquier repaso de comandos útiles de Linux. Pero apuntan a preguntas distintas, y confundirlas es la causa de la mayoría de las búsquedas fallidas.
find responde preguntas sobre los atributos de un archivo o directorio: nombre, tipo, fecha de modificación, tamaño. Recorre el árbol de directorios y evalúa cada entrada, sin abrir nunca el archivo para ver qué hay escrito adentro.
grep —de global regular expression print, heredado de un comando del editor ed— hace lo opuesto: lee cada archivo línea por línea y lo compara contra un patrón de texto o una expresión regular (una secuencia que describe un conjunto de cadenas posibles, no una sola palabra). Su salida son líneas que coinciden, no rutas.
Uno ejecuta el comando por archivo; el otro agrupa varios en menos invocaciones y suele ser más eficiente.
Sin este par, un nombre con espacios se corta en dos argumentos al pasar por una tubería.
En las básicas hay que escapar +, ?, | y paréntesis; en las extendidas (-E) son directos; PCRE (-P) no es universal.
Para atributos, find; para contenido, grep; para las dos cosas a la vez, una tubería.
Cómo buscar archivos con find
La sintaxis general de find es find [ruta...] [expresión]. Si no indicás una ruta, busca desde el directorio actual. La expresión combina pruebas (condiciones sobre cada entrada) y, si hace falta, acciones sobre lo que encuentra; sin una acción explícita, find simplemente imprime la ruta de cada coincidencia.
find . -name "*.log"
find /var/log -type f -name "*.log"
find . -type d -name "node_modules"
find /home/usuario -mtime -7
find . -size +100M
find /var/www -type f -name "*.php" -mtime -1
La primera busca archivos .log desde el directorio actual; la segunda limita el tipo y la ruta a /var/log, uno de los directorios que la estructura de directorios de Linux (FHS) reserva para registros del sistema; la tercera busca directorios node_modules; la cuarta lista lo modificado en la última semana; la quinta filtra por tamaño; la última combina tipo, nombre y fecha en una sola expresión.
| Prueba u opción | Qué evalúa | Ejemplo |
|---|---|---|
-name / -iname | Patrón sobre el nombre del archivo; -iname no distingue mayúsculas | find . -iname "*.pdf" |
-type f, d, l | Tipo de entrada: archivo, directorio o enlace simbólico | find . -type d |
-mtime -n / +n | Días desde la última modificación, con signo | find . -mtime -7 |
-size | Tamaño con sufijos c, k, M, G | find . -size +100M |
-maxdepth n | Limita la profundidad del recorrido | find . -maxdepth 1 |
-empty | Archivos o directorios vacíos | find . -type f -empty |
-newer archivo | Más reciente que un archivo de referencia | find /etc -newer /etc/hostname |
Por defecto find une varias pruebas con un «y» lógico implícito: una entrada tiene que cumplirlas todas para aparecer en el resultado.
Acciones de find: -exec {} \; frente a {} + y -delete
Encontrar rutas no siempre alcanza: a veces hace falta hacer algo con cada una, y las dos formas de cerrar -exec se comportan de manera muy distinta.
-exec comando {} \; ejecuta el comando una vez por cada archivo; {} se reemplaza por la ruta, y el punto y coma se escapa con \ porque, sin escapar, la terminal lo tomaría como el fin de su propia instrucción. Con mil archivos, arranca mil procesos, uno detrás de otro.
-exec comando {} + agrupa tantos nombres como puede en cada invocación, como xargs: resuelve el mismo trabajo con uno o unos pocos procesos. Por eso conviene siempre que el comando acepte varios argumentos —chmod, rm, grep—; {} \; solo tiene sentido si cada invocación necesita ser independiente.
# Una invocación por archivo: más procesos, más lento en árboles grandes
find . -name "*.tmp" -exec rm {} \;
# Una sola invocación agrupando varios archivos: más eficiente
find . -name "*.tmp" -exec rm {} +
# Dar permisos de ejecución a todos los scripts .sh de una vez
find . -type f -name "*.sh" -exec chmod +x {} +
find también trae -delete, más directa que -exec rm {} \; porque no depende de otro proceso. Antes de borrar de verdad:
- Corré primero la misma expresión con
-printy revisá la lista completa. - Restringí ruta y pruebas todo lo posible antes de una acción destructiva.
-deleteno pide confirmación ni usa papelera: es irreversible.
El error más común: espacios, -print0 y xargs -0
Por defecto, find imprime una ruta por línea. El problema aparece al enviar ese resultado por una tubería a xargs —el comando que convierte líneas de entrada en argumentos de otro comando—, porque sin opciones separa los argumentos por espacios y saltos de línea. Un archivo llamado informe final.txt se parte en dos argumentos, informe y final.txt, y el comando siguiente recibe dos rutas inexistentes en vez de una.
# Se rompe si algún nombre tiene espacios
find . -name "*.txt" | xargs grep -l "REVISAR"
# Sobrevive a espacios, saltos de línea y comillas en el nombre
find . -name "*.txt" -print0 | xargs -0 grep -l "REVISAR"
La solución es el par -print0 y xargs -0. -print0 le dice a find que termine cada ruta con un byte nulo en lugar de un salto de línea; xargs -0 interpreta la entrada de esa misma manera. Como un byte nulo nunca forma parte de un nombre de archivo válido en Linux, sirve como separador inequívoco: no importa si el nombre tiene espacios, tabulaciones o comillas, llega entero al otro lado de la tubería. Es, con diferencia, el error más frecuente al combinar find con grep a través de xargs.
Cómo buscar texto con grep
Esta sección retoma un aporte de la comunidad: el hilo «A brief introduction to Linux | Part XI: Expresiones regulares y Metacaracteres», de TerminusRoot en el foro de Underc0de, ya explicaba con ejemplos reales buena parte de lo que sigue —-v, -n, -i, -E, las anclas ^ y $, el punto como comodín y el escapado con \—. Sigue vigente; esta guía lo reorganiza junto con la parte de find, sin hilo equivalente en el foro.
La sintaxis general es grep [opciones] patrón [archivo...]: lee cada archivo línea por línea y, por defecto, imprime las líneas donde aparece el patrón.
grep -n "error" /var/log/syslog
grep -i "error" /var/log/syslog
grep -v "^#" /etc/ssh/sshd_config
grep -rl "REVISAR" ./src
grep -r --include="*.py" "import os" .
La primera muestra coincidencias de «error» con número de línea; la segunda hace lo mismo sin distinguir mayúsculas; la tercera invierte la búsqueda y muestra lo que no empieza con #, útil para revisar la configuración activa de un archivo lleno de comentarios; la cuarta busca de forma recursiva y solo lista los archivos con coincidencias; la última limita esa búsqueda a archivos .py.
| Opción | Qué hace | Ejemplo |
|---|---|---|
-r / -R | Búsqueda recursiva dentro de directorios | grep -r "REVISAR" ./src |
-i | Ignora mayúsculas y minúsculas | grep -i "error" registro.log |
-n | Muestra el número de línea de cada coincidencia | grep -n "error" registro.log |
-l | Solo lista los nombres de archivo con coincidencias | grep -rl "REVISAR" ./src |
-v | Invierte la coincidencia: imprime lo que no matchea | grep -v "^#" archivo.conf |
-E | Activa expresiones regulares extendidas (ERE) | grep -E "fail|error" registro.log |
-F | Interpreta el patrón como cadena fija, sin regex | grep -F "a+b" archivo.txt |
--include=PATRÓN | Limita la búsqueda recursiva a archivos que matcheen el patrón | grep -r --include="*.py" "import os" . |
BRE, ERE y PCRE: qué cambia de verdad
Una expresión regular es un patrón que describe un conjunto de cadenas posibles, no una sola palabra literal. POSIX define dos modos, y GNU grep agrega un tercero que ya no es POSIX.
Las expresiones regulares básicas (BRE) son el modo por defecto de grep. En este modo, metacaracteres como +, ?, |, ( y ) no tienen significado especial a menos que los escapes con una barra invertida: \+, \?, \|, \(, \). Las expresiones regulares extendidas (ERE, con -E) invierten la regla: esos símbolos tienen significado especial de forma directa, y escaparlos se lo quita.
# BRE (por defecto): la alternancia necesita escape
grep "fail\|error" registro.log
# ERE: la alternancia es directa
grep -E "fail|error" registro.log
# Anclas de comienzo y fin de línea, iguales en BRE y ERE
grep "^root:" /etc/passwd
grep "bash$" /etc/passwd
# BRE: el "?" opcional necesita escape
grep "colou\?r" texto.txt
# ERE: el "?" es directo
grep -E "colou?r" texto.txt
# PCRE, no garantizado en todas las implementaciones de grep
grep -P "\d{3}-\d{4}" contactos.txt
Las anclas ^ y $ y el punto . como comodín funcionan igual en los dos modos POSIX; lo que cambia es solo el tratamiento de los metacaracteres de agrupación y repetición.
| Modo | Cómo se activa | Metacaracteres + ? ( ) | Disponibilidad |
|---|---|---|---|
| BRE (básicas) | Modo por defecto de grep | Hay que escaparlos con \ para que sean especiales | Garantizada por POSIX en cualquier grep |
| ERE (extendidas) | grep -E | Tienen significado especial de forma directa | Garantizada por POSIX en cualquier grep |
| PCRE | grep -P (GNU grep) | Igual que ERE, más construcciones no POSIX (\d, \w, lookahead) | No garantizada en todas las implementaciones |
Si un patrón con |, + o ? no hace lo que esperás, fijate si estás en BRE sin escapar el símbolo, o si olvidaste -E.
Combinar find y grep con una tubería
La guía de redirecciones y tuberías en la terminal cubre la mecánica general de conectar la salida de un comando con la entrada del siguiente. Acá importa por qué conviene unir find y grep: ninguno cubre solo una búsqueda que combine atributos y contenido.
# Archivos .log que contienen "OutOfMemory"
find . -name "*.log" -print0 | xargs -0 grep -l "OutOfMemory"
# Archivos de /etc modificados después de /etc/hostname, que mencionan PermitRootLogin
find /etc -type f -newer /etc/hostname -print0 | xargs -0 grep -l "PermitRootLogin"
# Scripts Python modificados en los últimos 30 días con una marca REVISAR pendiente
find . -type f -name "*.py" -mtime -30 -print0 | xargs -0 grep -n "REVISAR"
# Alternativa sin xargs: -exec ya pasa el nombre completo, no hace falta -print0
find . -name "*.conf" -exec grep -l "Listen" {} +
El último ejemplo importa: con -exec grep ... {} +, find pasa los nombres directamente al comando, así que el problema de los espacios ni aparece. Estos patrones son los que después vas a encapsular dentro de un script de Bash para repetirlos con variables en lugar de reescribirlos cada vez.
Errores frecuentes
- Combinar find con xargs sin -print0/-0. Funciona con nombres simples y se rompe con el primer archivo que tiene un espacio.
- Elegir {} \; por costumbre en árboles grandes. Si el comando acepta varios argumentos, {} + hace el mismo trabajo con menos procesos.
- Usar
|en grep básico sin -E ni escaparla. En BRE,|es literal hasta que lo escapás o activás -E. - Creer que grep -i y find -iname cubren lo mismo. Uno mira el contenido; el otro, el nombre del archivo.
- Correr -delete o -exec rm sin probar antes con -print. Ninguna pide confirmación ni tiene deshacer.
- Dejar el patrón sin comillas. La terminal puede expandir comodines antes de que grep o find los reciban.
Preguntas frecuentes
¿Cuál es la diferencia entre buscar por metadatos con find y buscar contenido con grep?
find recorre un árbol de directorios y evalúa los atributos de cada entrada —nombre, tipo, fecha de modificación, tamaño— sin mirar el contenido. grep hace lo opuesto: lee cada archivo línea por línea y compara el texto contra un patrón. Ninguno reemplaza al otro: find filtra por atributos, grep filtra por contenido, y se combinan con una tubería cuando la búsqueda necesita ambas cosas, por ejemplo archivos recientes que además contengan cierta palabra.
¿Cómo busco archivos por nombre, tipo, fecha o tamaño?
Con las pruebas de find: -name o -iname por nombre, -type f o -type d por si es archivo o directorio, -mtime -7 por fecha de modificación, y -size +100M por tamaño. Se combinan en una sola expresión: find /var/log -type f -name "*.log" -mtime -7 -size +10M filtra las cuatro cosas a la vez. Con -maxdepth n limitás cuántos niveles recorre antes de evaluar cada prueba.
¿Cuándo uso -exec {} \; y cuándo -exec {} + o -print0 con xargs -0?
-exec comando {} \; ejecuta el comando una vez por archivo: más lento en árboles grandes porque arranca un proceso por coincidencia, pero sirve si cada invocación debe ser independiente. -exec comando {} + agrupa varios nombres por invocación y lanza muchos menos procesos, ideal si el comando acepta varios argumentos, como chmod o rm. -print0 con xargs -0 resuelve otro problema: pasar nombres con espacios por una tubería sin que se corten en dos argumentos.
¿Qué hace cada opción común de grep?
-r o -R busca recursivo; -i ignora mayúsculas; -n muestra el número de línea; -l solo lista archivos con coincidencias; -v invierte el resultado; -E activa expresiones regulares extendidas; -F trata el patrón como cadena literal; y --include="*.py" limita la búsqueda recursiva a ese patrón de nombre. Se combinan: grep -rn --include="*.py" "import os" . busca recursivo, solo en .py, con número de línea.
¿Qué es una expresión regular básica frente a una extendida y a PCRE?
POSIX define dos modos. Las básicas (BRE), modo por defecto de grep, no dan significado especial a +, ?, | ni a los paréntesis salvo que los escapes con \. Las extendidas (ERE), con -E, les dan ese significado de forma directa. GNU grep suma un tercer modo con -P: expresiones compatibles con Perl (PCRE), con construcciones no POSIX como \d o el lookahead, no garantizadas en todas las implementaciones de grep.
¿Por qué combinar find y grep con una tubería en vez de usar solo uno de los dos?
Porque cada uno resuelve la mitad del problema: find no mira contenido y grep no filtra por metadatos. Cuando la búsqueda combina ambos criterios, find selecciona las rutas y grep revisa su contenido. La forma segura es find ... -print0 | xargs -0 grep ..., porque el byte nulo evita que un nombre con espacios se parta en dos argumentos, el error más común al combinarlos.
Fuentes
Aportes de la comunidad y documentación oficial consultados para esta guía. Fecha de consulta: 29 de julio de 2026.
Aportes de la comunidad Underc0de
- Underc0de, foro. A brief introduction to Linux | Part XI: Expresiones regulares y Metacaracteres, por TerminusRoot, sección GNU/Linux. Origen de la sección de grep y expresiones regulares de esta guía: cubre -v, -n, -i, -E, las anclas ^ y $, el punto como comodín y el escapado con barra invertida, y sigue vigente.
La parte de find de esta guía no se apoya en ningún hilo del foro: no existe un aporte previo de la comunidad sobre este comando, así que esa sección es contenido nuevo. La parte VI de la misma serie de TerminusRoot, «Operaciones de Archivos y Directorios», es una lectura relacionada sobre manejo de archivos en la terminal, pero no trata find.
Documentación oficial
- man7.org. find(1). Sintaxis completa de pruebas y acciones de find.
- man7.org. grep(1). Opciones de grep y comportamiento por defecto.
- man7.org. xargs(1). Comportamiento de -0 y el problema de separación por espacios.
- GNU. GNU grep Manual. Detalle de BRE, ERE y las extensiones PCRE de GNU grep.
- GNU. GNU Findutils Manual. Referencia extendida de find, incluida la diferencia entre -exec {} \; y -exec {} +.
- The Open Group. POSIX Base Specifications — grep. Definición estándar del comportamiento de grep.
- The Open Group. POSIX Base Specifications — find. Definición estándar de find.
- The Open Group. POSIX Base Specifications — Regular Expressions. Definición formal de BRE y ERE.