HOWTO · Bash

Ejecute el comando find -exec en Bash

Este artículo explica cómo usar la acción -exec de find para ejecutar comandos sobre rutas seleccionadas por find; grep busca texto dentro del contenido de los archivos.

En esta página

find selecciona rutas del sistema de archivos; grep busca en el contenido de los archivos. La acción -exec conecta ambas tareas al pasar cada ruta seleccionada como argumento a otro comando. Esta guía presenta una sintaxis reutilizable, búsquedas en el contenido, la diferencia entre ejecutar una vez por coincidencia y agrupar rutas, y operaciones prudentes con archivos.

Cómo funciona find -exec

find comienza en el directorio que indiques, evalúa pruebas como el tipo, el nombre, la antigüedad o el tamaño del archivo, y recorre las rutas coincidentes. Con -exec, ejecuta el comando que indiques y sustituye {} por cada ruta coincidente. La ruta se pasa como argumento, por lo que los espacios, las tabulaciones, las comillas y los caracteres comodín de un nombre de archivo no vuelven a interpretarse en un shell. Esto es más seguro que construir una cadena de comandos o pasar nombres separados por saltos de línea a otro comando.

La búsqueda y la acción son tareas distintas: un predicado como -name '*.txt' selecciona archivos, mientras que un comando como grep lee su contenido. Añade -type f si la acción debe aplicarse solo a archivos regulares. De forma predeterminada, find también considera directorios, así que elige predicados que coincidan con el tipo de entrada que espera el comando.

Sintaxis básica de find -exec

La forma reutilizable es find STARTING_PATH TESTS -exec COMMAND {} \;. STARTING_PATH define el árbol que se buscará; las pruebas limitan qué rutas llegan a la acción; COMMAND y sus opciones especifican la tarea; y {} indica dónde find inserta una ruta. En un shell interactivo, escribe el terminador como \; para que el shell pase un punto y coma literal a find. Sin ese escape o unas comillas, el shell interpreta el punto y coma como separador de comandos.

Pon entre comillas los patrones de nombres, como '*.txt'. Así, el shell pasa el patrón intacto y find puede comparar los nombres de cada ruta visitada, en vez de expandir el patrón con los archivos del directorio actual. Para que las rutas que empiezan con un guion no se confundan con opciones del comando, indica explícitamente un directorio inicial, por ejemplo ./-archive.

Ejecuta este ejemplo:

El código y las etiquetas o salidas visibles de esta sección se mantienen en inglés.

set -eu
root=$(mktemp -d)
trap 'rm -rf "$root"' EXIT
mkdir -p "$root/notes"
printf 'report: first\nkeep this line\n' > "$root/notes/weekly report.txt"
printf 'draft only\n' > "$root/notes/draft.txt"
find "$root" -type f -name '*.txt' -exec grep -nH 'report' {} +

El ejemplo crea un directorio pequeño, busca solo archivos de texto y pide a grep que imprima los números de las líneas coincidentes y los nombres de archivo. -H mantiene visible el nombre del archivo incluso cuando una invocación recibe una sola ruta. El directorio temporal se elimina al salir del shell. El código y las etiquetas o salidas visibles de esta sección permanecen en inglés. Es una demostración ejecutable; aquí no se afirma ningún resultado capturado.

Buscar en el contenido de archivos con find y grep

Para buscar texto dentro de /documents, usa find /documents -type f -name '*.txt' -exec grep -nH 'report' {} +. find selecciona los archivos de texto candidatos y grep imprime cada línea coincidente con su ruta y número de línea. Usa grep -l en lugar de -nH si solo necesitas los nombres de los archivos que contienen una coincidencia. Un archivo puede tener varias líneas coincidentes, por lo que el formato por línea puede mostrar la misma ruta más de una vez.

La cadena de búsqueda se pasa como un único argumento literal porque está entre comillas. Si usas una expresión regular, define la expresión con cuidado; para buscar una cadena fija literal, grep -F evita interpretar los metacaracteres de las expresiones regulares. La búsqueda puede no leer un archivo por falta de permisos o por su codificación; si automatizas el proceso, ten en cuenta los mensajes de diagnóstico y el estado de salida del comando. No se indican rutas de ejemplo porque los resultados dependen de los archivos presentes en el directorio del lector.

Elegir entre ; y +

Con -exec COMMAND {} \;, find ejecuta el comando por separado para cada ruta coincidente. Esta forma es fácil de entender y funciona con comandos diseñados para procesar una ruta a la vez. El punto y coma escapado para el shell termina la definición de la acción; no forma parte del comando que se ejecuta.

Con -exec COMMAND {} +, find pasa varias rutas coincidentes a cada invocación del comando y las divide en grupos que respetan el límite de tamaño de argumentos del sistema. Coloca {} una sola vez, como último argumento del comando inmediatamente antes de +. Agrupar rutas suele reducir la sobrecarga de iniciar procesos para herramientas como grep, pero no cambia lo que hacen con cada archivo y no resulta útil para un comando cuyo funcionamiento depende de recibir exactamente una ruta. El signo más se pasa directamente a find; no hace falta escaparlo para el shell.

Ejecutar otros comandos con seguridad en los archivos coincidentes

Antes de eliminar registros antiguos, haz una primera prueba con -print e inspecciona las rutas que muestra: find /var/log -type f -name '*.log' -mtime +30 -print. La prueba -mtime +30 selecciona archivos cuya fecha de modificación es de hace más de 30 periodos completos de 24 horas; no significa «más antiguos que el trigésimo día del calendario». Después de comprobar la selección y confirmar que tienes los permisos necesarios, GNU y muchas otras implementaciones de find admiten -delete, como en find /var/log -type f -name '*.log' -mtime +30 -delete. Este comando elimina los archivos de forma irreversible; verifica el directorio inicial y los predicados antes de usarlo.

Para mover archivos regulares de más de 100 mebibytes desde un árbol de descargas, primero inspecciona find /downloads -type f -size +100M -print. Si la lista es correcta y /archive/ existe en el mismo sistema con los permisos adecuados, puedes ejecutar una acción por archivo: find /downloads -type f -size +100M -exec mv -- {} /archive/ \;. La prueba de tamaño +100M usa las unidades de tamaño de find y redondea a la unidad siguiente; si importa un umbral exacto en bytes, confirma las convenciones de unidades de la implementación. Al mover archivos, puede sobrescribirse un archivo o producirse un conflicto con un nombre que ya exista en el destino; comprueba si hay nombres base duplicados antes de ejecutar el comando. Para cualquiera de estas tareas, limita los criterios de selección y revisa la vista previa antes de modificar archivos.