find -exec tar
Una tarea convecional hoy en día cuando se manejan servidores tales como unix es la de respaldar información y manejar logs de errores. Por lo general, algunos archivos son estrictamente necesarios, conservalos seria de mucha importancia cuando se presente un problema en el server. Otro problema común es cuando los archivos de logs crecen mucho y que poco a poco van llenando el servidor.
Ambas situaciones se pueden arreglar usando el comando tar.
Para el primer caso el comando tar nos sirve para empaqueter los archivos necesarios y luego descargarlos a nuestra maquina local. La segunda situación y en la que nos vamos a enfocar es en los logs, donde con ayuda de este comando vamos a comprimir los archivos mas grandes y aliviar el espacio en nuestro host.
Veamos el uso del comando tar para la segunda situación.
Si queremos empaquetar todo el directorio completo de los logs seria:
tar -cvf paquete_logs.tar /directorio/de/los/logs
Donde paquete_logs.tar es el nuevo paquete que con los logs empaquetados y /directorio/de/los/logs es el directorio que vamos a empaquetar. Sin embargo. a pesar de que es el comando esta correcto no es el mas indicado, pues dentro de ese directorio pueden haber otros tipos de archivos que no sean logs, y que de pronto no es conveniente enpaquetatarlos. Para ello necesitamos seleccionar unicamente los logs y dejar de lago el resto de archivos y directorios que no estan contemplados como logs.
Ahora supongamos que dentro del directorio de logs tenemos los siguientes archivos:
- a.log
- a.txt
- b.log
- b.txt
- c.log
- c.txt
- result.lst
- config
- temp (directorio)
- more.log (directorio)
Ahora queremos unicamente empaquetar los archivos .log por lo cual se debe usar otro comando llamando find que nos permite crear un filtro de los archivos a empaquetar, para que luego sean empaquetas en un tar. El find no solo permite crear un filtro por nombre, sino también permite reconocer archivos de directorios, así mismo permite crear filtros por fecha de modificación y otros más, para nuestro ejemplo solo vamos a usar el filtro por nombre (para seleccionar todo lo que sea .log) y por tipo (para seleccionar solo archivos y no directorios) veamos:
Creamos una archivo tar que servirá para meter en él todos nuestros logs:
touch files.tar
El find y el tar puede ejecuartarse en una sola línea siempre y cuando especifiquemos dicha unión con un -exec. El comando -exec permite concatenar instrucciones de manera que el resultado de una primera instrucci[on sirva como par[rametro para una segunda intruccci[on. En este caso, el resultado del uso del find le sirve al comando tar saber que archivos debe empaquetar. El ejemplo completo quedaría algo así:
find /directorio/de/los/logs -name '*.log' -type f -exec tar -rvPf "files.tar" '{}' \;
La instruccion find lleva tres parámetros muy útiles, el path donde se desea hacer la busqueda, es decir /user/var/logs, seguidamente le indicamos que busque dentro de ese directorio todo lo que en su nombre tenga alguna cadena de caracteres .log en su nombre (incluye archivos y directorios) con ayuda del -name ‘*.log’, el * (asterisco) indica que no importarta lo uqe haya antes del .log en nombre, pues solo nos importa encontrar dicha terminación y por último debemos especificar que solo seleccione archivos y no directorios, acá hay que aclarar que el directorio more.log que a pesar de tener en su nombre los caracteres .log será ser excluido ya que el filtro -type f solo incluirá archivos evitando los directorios. Finalmente, por formato de toda la instrucción debemos tomar el resultado del find y pasárselo al tar que se logra con ‘{}’ (llaves vacías), y para cerrar todos los comandos por definición termiamos con \;.
El resultado de lo anterior genera un archivo tar llamado files.tar que contiene los siguientes archivos:
- a.log
- b.log
- c.log
Excelente apunte, era lo que necesitaba para buscar y a la vez comprimir cuando tenia archivo regados en diff carpetas. Thanks you.
Hola,
Te recomiendo que uses xargs con find y no uses -exec, ya que es mucho más rapido (esto es así porque -exec crea un proceso por cada uno de los argumentos que se le pasa, en cambio xargs no hace un fork de cada argumento pasado)
Un ejemplo como el tuyo, pero con imagenes .jpg por ejemplo, fijate en la enorme diferencia en los tiempos de respuesta (de 57 segundos a 31 MINUTOS):
skeksi@jalejonias ~ $ time find . -name ‘*.jpg’ -type f -exec tar -rf kaka.tar ‘{}’ \;
real 31m48.947s
user 4m3.095s
sys 27m18.434s
skeksi@jalejonias ~ $ time find . -name ‘*.jpg’ -type f -print0 | xargs -0 tar -rf imagenes.tar
real 0m57.306s
user 0m0.540s
sys 0m3.556s
El fichero imagenes.tar me ocupaba 1 GB xDD
Haz pruebas y verás que la diferencia es notable.
Busca en google xargs vs -exec y verás que hay un montón de artículos al respecto.
pd: por cierto el touch files.tar, te sobra, ya que el tar con el -r, si no existe el fichero a crear lo crea, pruebalo ;D
Saludos
skeksi@jalejonias ~ $ time find . -name ‘*.jpg’ -type f -exec tar -rf imagenes.tar {} +
real 0m40.742s
user 0m0.536s
sys 0m3.316s
Acabo de descubrir que si le pones un + al final del exec en vez del \; permite que le pases todos los argumentos de golpe sin tener que crear un fork de cada argumento. Y el resultado es mejor que con el xargs.
Luego, nos quedamos con el -exec orden {} +
ciao