A veces puede ser útil tener un script que detecte si los contenidos de un directorio han cambiando desde la última vez que se ejecutó el script, pero excluyendo algunos de los ficheros o directorios que hay dentro. Esto puede usarse, entre otras cosas, para hacer copias de seguridad, por ejemplo: hay situaciones en las que, en lugar de hacer una copia de seguridad incremental, uno puede querer hacer una copia completa, pero solo si hay cambios. Nótese que no estoy hablando de monitorizar un directorio en tiempo real para detectar cambios (para eso, mira inotify
).
Haciéndolo con stat
Para chequear un directorio completo sin excluir nada dentro de él, es suficiente utilizar stat
.
Podrías usar un script como el siguiente:
DIR_TO_CHECK='/dir/to/check' OLD_STAT_FILE='/home/johndoe/old_stat.txt' if [ -e $OLD_STAT_FILE ] then OLD_STAT=`cat $OLD_STAT_FILE` else OLD_STAT="nothing" fi NEW_STAT=`stat -t $DIR_TO_CHECK` if [ "$OLD_STAT" != "$NEW_STAT" ] then echo 'Directory has changed. Do something!' # do whatever you want to do with the directory. # update the OLD_STAT_FILE echo $NEW_STAT > $OLD_STAT_FILE fi
Su funcionamiento es bastante sencillo. El script de alguna manera tiene que monitorizar los resultados de haber ejecutado stat
sobre el directorio de una vez para otra. Para hacer esto, simplemente usa un fichero de texto (especificado por la variable OLD_STAT_FILE): si el fichero existe, se cargará su contenido en la variable OLD_STAT, y si no, se inicializará la variable OLD_STAT con cualquier cosa (‘nothing’ en el ejemplo).
Después, el script simplemente ejecuta stat
en el directorio, y compara el resultado con el valor de OLD_STAT, si son diferentes significa que algo cambió en el directorio. En ese caso, puedes hacer lo que quieras (hacer copia de seguridad del directorio, o lo que sea), y entonces es necesario actualizar los contenidos del fichero de texto donde guardas el resultado de stat -t
.
Excluyendo cosas del directorio
Si queremos chequear si algo en el directorio ha cambiado pero excluyendo uno o más ficheros o directorios dentro del directorio principal, podemos hacerlo de otra manera. El proceso general es el mismo: monitorizar un “estado antiguo” del directorio, y compararlo con el “nuevo estado”, pero en lugar de utilizar stat
podemos usar una serie de comandos.
Aquí está el código del nuevo script:
DIR_TO_CHECK='/dir/to/check' PATH_TO_EXCLUDE="/dir/to/check/tmp*" OLD_SUM_FILE='/home/johndoe/old_sum.txt' if [ -e $OLD_SUM_FILE ] then OLD_SUM=`cat $OLD_SUM_FILE` else OLD_SUM="nothing" fi NEW_SUM=`find $DIR_TO_CHECK/* \! -path "$PATH_TO_EXCLUDE" -print0| xargs -0 du -b --time --exclude=$PATH_TO_EXCLUDE | sort -k4,4 | sha1sum | awk '{print $1}'` if [ "$OLD_SUM" != "$NEW_SUM" ] then echo "Directory has changed. Do shomething!" # do whatever you want to do with the directory. # update old sum echo $NEW_SUM > $OLD_SUM_FILE fi
stat
vamos a usar la suma sha1 (sha1sum
) de algopara controlar si algo ha cambiado o no. La línea clave en este script es cuando asignamos el valor de NEW_SUM
, veámoslo:
find $DIR_TO_CHECK/* \! -path "$PATH_TO_EXCLUDE" -print0
: Primero obtenemos una lista de todos los ficheros en el directorio confind
. Utilizando el parámetro-path
precedido de\!
le decimos afind
que excluya la ruta especificada. Puedes especificar más de una ruta repitiendo esa misma estructura (\! -path $PATH_1 \! -path $PATH_2 ...
). Utiliamos -print0 para forzar afind
a que separe los nombres de archivos con un carácter nulo, en lugar de un retorno de línea (necesitamos que sea así para pasar los datos axargs
a través del pipe).xargs -0 du -b --time --exclude=$PATH_TO_EXCLUDE
: Obtenemos una lista de todos esos ficheros (excluyendo la ruta o rutas que queramos ignorar) con su uso de disco (tamaño), y un día y hora de última modificación. Es decir, cada línea de la salida de este comando tiene la forma “<tamaño> <día>”.sort -k4,4
: Ordenamos la lista previa por el cuarto campo, que es la ruta completa del fichero o directorio. Esta lista ordenada, de algún modo, refleja el “estado” de todo el directorio. Si un fichero o directorio es añadido, eliminado, o renombrado, o el tamaño o tiempo de modificación de cualquier línea en esta lista cambia, esta lista reflejará dicho cambio.sha1sum
: Una suma (por ejemplo la suma sha1) del la lista anterior es una manera de “codificar” el estado de nuestro directorio (excluyendo lo que queramos excluir). Así pues, en este punto, al hacer lasha1sum
de esta lista obtenemos un dato que codifica de alguna manera un estado concreto del directorio.awk '{print $1}'
: Hacemos esto simplemente para limpiar un poco la salida desha1sum
.
Esto es todo. Cada vez que se ejecute el script, calculará esta suma clave. Si la suma actual difiere de la vieja (que se leyó del fichero), podemos estar seguros de que algo cambió en el directorio.
Gracias a jPablo128