5.2. find: busca archivos en función de ciertos criterios

find es un utilitario de Unix muy antiguo. Su rol es buscar recursivamente uno o más directorios y encontrar archivos que se correspondan con un cierto conjunto de criterios en esos directorios. Aunque es muy útil, su sintaxis es verdaderamente compleja, y usarlo requiere cierta práctica. La sintaxis general es:

find [opciones] [directorios] [criterios] [acción]

Si no especifica directorio alguno, find buscará en el directorio corriente. Si no especifica el criterio, esto es equivalente a "verdadero", por lo que se encontrarán todos los archivos. Las opciones, criterios y acciones son tan numerosas que solo mencionaremos algunas de cada una. Comencemos por las opciones:

Un criterio puede ser uno o más de varias pruebas atómicas; algunas pruebas útiles son:

Existen muchas otras pruebas, debe referirse a la página Man para más detalles. Para combinar las pruebas, Ud. puede utilizar uno de:

Finalmente, puede especificar una acción para cada archivo encontrado. Las acciones más usadas frecuentemente son:

¿Todavía está aquí? Está bien, ahora practiquemos un poco, ya que todavía es la mejor forma de entender a este monstruo. Digamos que quiere encontrar todos los directorios en /usr/share. Entonces ingresará:

find /usr/share -type d

Suponga que tiene un servidor HTTP, todos sus archivos HTML están en /var/www/html, que coincide con su directorio corriente. Ud. desea encontrar todos los archivos que no se modificaron en el último mes. Debido a que tiene páginas de varios autores, algunos archivos tienen la extensión html y otros la extensión htm. Desea vincular estos archivos en el directorio /var/www/obsolete. Entonces ingresará[1]:
find \( -name "*.htm" -o -name "*.html" \) -a -ctime -30 \
-exec ln {} /var/www/obsolete \;

Está bien, este es uno un poco complejo y requiere una pequeña explicación. El criterio es este:

\( -name "*.htm" -o -name "*.html" \) -a -ctime -30

que hace lo que queremos: encuentra todos los archivos cuyos nombres terminan con .htm o con .html "\( -name "*.htm" -o -name "*.html" \)", y (-a) que no han sido modificados en los últimos 30 días, lo que es más o menos un mes (-ctime -30). Note los paréntesis: aquí son necesarios, porque -a tiene una precedencia mayor. Si no hubiera paréntesis alguno, se hubieran encontrado todos los archivos que terminen con .htm, y todos los archivos que terminen con .html y que no han sido modificados por un mes, que no es lo que nosotros queremos. Note también que los paréntesis están desactivados para el shell: si hubiésemos puesto ( .. ) en vez de \( .. \), el shell los hubiese interpretado y tratado de ejecutar -name "*.htm" -o -name "*.html" en un sub-shell... Otra solución podría haber sido poner los paréntesis entre comillas simples o dobles, pero aquí es preferible una contra-barra ya que solo tenemos que aislar un solo caracter.

Y finalmente, está el comando a ejecutar para cada uno de los archivos:

-exec ln {} /var/www/obsolete \;

Aquí también, tiene que desactivar el ; para el shell, ya que de no ser así el shell lo interpretaría como un separador de comandos. Si no lo hace, find se quejará que le falta un argumento a -exec.

Un último ejemplo: tiene un directorio enorme denominado /shared/images, con todo tipo de imágenes en él. Regularmente, Ud. usa el comando touch para actualizar la fecha de un archivo denominado stamp en este directorio, para que tenga una referencia temporal. Ud. quiere encontrar todas las imágenes JPEG en el mismo que son más nuevas que el archivo stamp, y ya que Ud. obtuvo las imágenes de varias fuentes, estos archivos tienen las extensiones jpg, jpeg, JPG o JPEG. También quiere evitar buscar en el directorio old. Quiere que se le envíe la lista de estos archivos por correo electrónico, y su nombre de usuario es darth:

find /shared/images -cnewer     \
     /shared/images/stamp       \
     -a -iregex ".*\.jpe?g"     \
     -a -not -regex ".*/old/.*" \
       | mail darth -s "Imagenes nuevas"

¡Y eso es todo! Por supuesto, este comando no es muy útil si tiene que ingresarlo cada vez, y quisiera ejecutarlo regularmente... Puede hacer lo siguiente:

Notas

[1]

Note que este ejemplo necesita que /var/www y /var/www/obsolete ¡estén en el mismo sistema de archivos!


Tux sobre Estrella por MandrakeSoft Linux es una marca registrada de Linus Torvalds. Todas las otras marcas registradas y copyrights son la propiedad de sus respectivos dueños.
A menos que se diga lo contrario, todo el contenido de estas páginas y todas las imágenes tienen Copyright de MandrakeSoft S.A. y de MandrakeSoft Inc. 2000.
http://www.linux-mandrake.com/