Si buscas encontrarás: find en Linux

Publicado el 01 marzo 2016 por Drassill
Cualquiera que haya usado Linux desde la consola sabe que uno de los principales quebraderos de cabeza de uno es la búsqueda de archivos dentro del sistema... Sin ayudas gráficas ni recursos "intuitivos" más de uno se vuelve loco usando diferentes combinaciones de los comandos cd, ls y grep, pero la mayoría de las veces no es necesario recurrir a dichos términos, pues afortunadamente existe un potentísimo buscador en Linux que puede ayudarnos a encontrar todo lo que necesitemos: El comando find. Desde búsquedas "simples" a búsquedas profundas, find puede ayudarnos a encontrar la aguja en el pajar en cuestión de segundos.

Para entender bien esta gran herramienta, lo primero que uno debe conocer a la perfección es la estructura sobre la que trabaja ésta pues regirá cualquier búsqueda que queramos hacer. Dicha estructura sería:
find directorio_búsqueda criterios_búsqueda acción_a_ejecutar

Estructura que si desgranásemos tendría el siguiente significado:
  • directorio_búsqueda: Ruta desde la que comenzar a buscar; en caso de haber directorios dentro de dicha ruta, también buscarían en éstos, con lo que si se comenzase a buscar desde el directorio raíz (/), comenzaríamos la búsqueda desde el directorio del que "cuelgan" el resto y buscaríamos en todo el sistema.
  • criterios_búsqueda: Después de especificar donde comenzar a buscar es necesario decir qué es lo que se desea buscar; esto se determina mediante una serie de criterios y parámetros que nos pueden ayudar a encontrar aquello que deseemos. Esta es la parte más importante del comando ya que es la que determinará qué es lo que se quiere encontrar.
  • acción_a_ejecutar: Tras encontrar lo que deseamos, podemos hacer que de forma OPCIONAL se ejecute algo; es decir que ejecute un comando sobre lo encontrado; esto es bastante delicado y dependiendo del tipo de acción es aconsejable extremar las precauciones.

Ahora que conocemos la estructura, si observamos bien veremos que lo más importante de todo son los criterios que deseamos utilizar para la búsqueda; criterios que dependiendo de su "potencia" son más usados que otros... Englobar todos ellos es complicado, más aún cuando hay muchos criterios que no son usados, pero hay otros muchos que sí, criterios en los cuales me quiero enfocar.
Lo más básico
Aunque find es muy potente y versátil, la mayoría de las búsquedas realizadas por los usuarios son relativamente sencillas, búsquedas que se pueden hacer únicamente conociendo las búsquedas más básicas que engloban tres criterios: El nombre del archivo/directorio, el usuario que es dueño de éste y (a veces) el grupo al que pertenece el susodicho. Son criterios simples que generalmente bastan para satisfacer la mayoría de las necesidades; criterios que usaríamos de la siguiente forma:
Para buscar un archivo por nombre podemos recurrir a diferentes medios, si bien todas las búsquedas por nombre están basadas en el criterio -name. En ejemplo de una búsqueda muy básica, sería la búsqueda de un archivo llamado texto.txt que se realizaría desde el directorio raíz:
find/-name"texto.txt"
La búsqueda por nombre va más allá de ésto... es decir que no solo se limita a buscar una cadena de texto fija; podemos jugar con diferentes rangos y valores para adaptar ese nombre a diferentes situaciones; por ejemplo:
Para buscar nombres que empiecen por a:
find/-name"a*"
Para buscar nombres que terminen en una letra minúscula
find/-name"*[a-z]"
Si queremos aplicar lo mismo que antes pero para cualquier letra:
find/-name"*[a-Z]"
Podemos usar rangos numéricos si lo deseamos:
find/-name"[0-9]*.txt"
Además -name posee un "hermano" llamado -iname que no realizaría distinciones entre mayúsculas y minúsculas, con lo que dependiendo para qué búsquedas puede resultarnos más útil que el criterio original.
Tal y como hemos visto antes, también tenemos la opción de buscar por usuario y grupo; aunque obviamente para ello habría que conocer bien esos conceptos... Una buena ayuda para saber a qué usuario y grupo pertenecen los archivos y directorios es el comando ls -la, pero esto ya depende de las preferencias de cada uno. A sabiendas de los usuarios y grupos existentes, ya seríamos capaces de realizar búsquedas en condiciones en base a dichos parámetros, con lo que si por ejemplo deseásemos buscar todos los archivos pertenecientes al usuario ivan tendríamos que recurrir al criterio -user tal que así:
find/-user ivan
En cambio si deseásemos encontrar todo lo que perteneciese al grupo con el mismo nombre, tendríamos que usar el criterio -group:
find/-group ivan
Obviamente todo esto es perfectamente combinable entre sí, y mediante estos pequeños criterios básicos podemos hacer búsquedas muy completas y potentes; por ejemplo:
find/var -name"[a-n][0-9]*.sh"-user ivan -grouptest
Búsquedas inversas y búsquedas por tipo
Las búsquedas básicas nos sacarán de la mayoría de los atolladeros, pero hay un par de criterios que aunque no son especialmente usados, son casi tan útiles como los anteriormente mostrados: Las búsquedas por tipo y las búsquedas inversas. El primer tipo de búsqueda se realiza usando el criterio -type seguido del tipo de archivo que deseamos encontrar; es más podemos decirle que lo que queremos encontrar es un directorio; he aquí un ejemplo:
find/-name"*[a-Z]"-type f
En este caso le hemos especificado que queremos encontrar únicamente archivos; existen obviamente más tipos; aunque hay muchos tipos de archivo, los más populares en éstas búsquedas serían:
  • f: Fichero regular
  • d: Directorio
  • l: Enlace simbólico.
  • s: Socket/puerto.
Nuestras búsquedas se van haciendo progresivamente más eficientes, ¿pero que pasaría si quisiésemos que buscase exactamente lo opuesto a lo especificado en un criterio? ¿Es decir que quisiésemos buscar por ejemplo todo aquello que no fuese del usuario ivan o que no fuese un fichero regular? Afortunadamente contamos con un criterio muy sencillo llamado -not que hace exactamente eso; CUIDADO: Dicho criterio -not únicamente sería válido para el siguiente criterio, es decir que si hubiesen dos criterios después del -not, éste únicamente afectaría al primero de ellos; es decir que si quisiésemos que la búsqueda inversa afectase a todos los criterios, habría que especificar -not en cada uno de estos. Una búsqueda inversa de ejemplo sería:
find/etc -name"[a-b]*[0-5]"-not-type d
Aquí diríamos que todo aquello que se buscase a partir del directorio /etc todo aquello que empezase por a o b, terminase entre el 0 y el 5 y que NO fuese un directorio.
Usando valores númericos para búsquedas avanzadas
Aunque los criterios básicos/intermedios nos otorgan un enorme poder de búsqueda, a veces esto no es suficiente y necesitamos más capacidad de búsqueda; búsquedas que ya están relacionadas con tamaños de archivos o con cantidad de minutos/días... Es decir, relacionadas con argumentos numéricos. Si bien es cierto que esto puede parecer que sea una búsqueda muy poco práctica,  en más de una ocasión estas búsquedas me han resultado enormemente útiles, especialmente para buscar ficheros muy grandes o muy pequeños... Aún así, antes de empezar a trabajar con los criterios usados para este tipo de búsquedas, es importante tener claros tres conceptos que, aunque a primera vista pueden parecer muy simples, nunca está de más tenerlos claros.
  • +número: Por ejemplo +36; esto significa que la búsqueda tendrá en cuenta todo aquello que sea mayor a dicho número.
  • -número: Por ejemplo -5; esto significa que la búsqueda tomará en cuenta aquello que sea menor a este número.
  • número: Por ejemplo 10; aquí únicamente se mostrará aquello que encaje exactamente con dicho número.

¿Sencillo cierto? Ahora que se tienen claro estos tres pequeños conceptos podríamos empezar a trabajar con las búsquedas relacionadas con números; números que generalmente se asocian a dos tipos de criterio: Tiempo desde que se modificó/leyó el fichero y tamaño de éste.
Para buscar un archivo por su tamaño habría que tener en cuenta que find únicamente es capaz de reconocer las siguientes unidades de medida:
  • k: Kilobytes
  • c: bytes
  • w: 2 bytes
  • b: 512 bytes

Al existir pocas unidades de medida, las he mostrado todas, si bien las más prácticas serían las búsquedas por kilobytes para la mayoría de archivos "comunes" y por bytes para archivos muy muy pequeños. Las otras dos unidades de medida, si bien es bueno saber que existen, no son apenas usadas en la actualidad. Cualquier búsqueda relacionada con el tamaño de un archivo se realiza mediante el criterio -size; criterio que podemos usar para que especificar archivos de un tamaño exacto o de un tamaño mayor/menor del especificado, otorgándonos cierta flexibilidad. Por ejemplo:
find/-size +100000k
También podemos hacer búsquedas dentro de un cierto rango de tamaño
find/-size +100000k -size-150000k
Por otro lado también podemos buscar archivos que hayan sido leídos y/o modificados recientemente gracias al uso de argumentos numéricos; esto es especialmente útil cuando se quieren realizar búsquedas delicadas en las que queramos saber si se ha leído o modificado un archivo en un periodo de tiempo en el que supuestamente no debería haber pasado. Aquí se usan diferentes criterios dependiendo de nuestras necesidades, si bien en este caso todos ellos son útiles a su manera:
  • -atime: Número de días desde que se ACCEDIÓ al fichero por última vez.
  • -mtime: Número de días desde que se MODIFICÓ el fichero por última vez.
  • -amin: Número de minutos desde que se ACCEDIÓ al fichero por última vez.
  • -mmin: Número de minutos desde que se MODIFICÓ el fihcero por última vez.
Si bien los criterios de búsqueda basados en minutos ofrecen una mayor flexibilidad que el de días, dependiendo de los rangos de tiempo en los que nos movamos, pueden ofrecernos resultados muy interesantes; al igual que con el tamaño podemos usar valores fijos o combinados con + o -, con lo que podemos realizar búsquedas tan interesantes como las siguientes:
Para ficheros modificados hace menos de 5 minutos podríamos recurrir al siguiente ejemplo:
find/-mmin-5
Si queremos ficheros accedidos hace menos de 1 día y modificados hace menos de 30 minutos podríamos recurrir a esta sentencia:
find/-atime-1-mmin-30
También podemos hacer búsquedas entre dos intervalos de tiempo para ser muy precisos:
find-mmin +10-mmin-20
Como podéis ver las posibilidades que ofrecen estos criterios numéricos son muy amplias, solo basta con jugar con éstos para adaptarlos lo mejor posible a nuestras búsquedas.
Ejecución de comandos
No puedo finalizar este post sin mencionar la ejecución de comandos; aquel punto tan "delicado" que he comentado en mi explicación inicial; imaginemos que hemos hecho una búsqueda muy avanzada y precisa ¿Qué hacemos después? ¿Usamos los comandos deseados sobre cada uno de ellos? NO. Eso sería dejar de lado la potencia que nos ofrece find. Tras poner todos los criterios necesarios para encontrar nuestros preciosos archivos, opcionalmente, podemos decidir qué hacer con ellos tras encontrarlos; existen diferentes acciones posibles (generalmente comandos que puede ejecutar find) si bien mi acción favorita es -exec ya que nos permite ejecutar cualquier comando como sin nos encontrásemos dentro de un shell. Cualquier comando lanzado mediante -exec tendría este aspecto:
-exec comando {} \;
{} Representaría el resultado obtenido del comando find mientras que los caracteres \; representarían el "fin" de la acción o comando a ejecutar tras la búsqueda... ¿Qué usos prácticos se le puede dar a esto? Esto depende de nuestras necesidades e imaginación, pero he aquí algunos ejemplos:
Si deseásemos eliminar archivos regulares que tuviesen un tamaño excesivamente grande podríamos escribir este comando:
find/-size + 1000000k -type f -execrm-f{} \;
Si deseásemos consultar el contenido de archivos que hayan sido modificados recientemente, que no excedan los 1000k de tamaño y queremos tener la certeza de que NO son directorios, este sería el comando:
find/-mmin-60-size-1000k-not-type-d-execcat{} \;
Como podéis observar find es una herramienta increíblemente potente y polivalente que con unos pocos criterios nos puede sacar de grandes apuros; el único límite en nuestras búsquedas, sería el impuesto por nuestra imaginación.
Espero que os haya resultado útil.
Saludos.