macos - fswatch - linux detect file system changes
Bash script, watch folder, execute command (12)
Estoy tratando de crear un script bash que tome 2 parámetros: un directorio y un comando. Necesito ver este directorio para ver los cambios y cuando algo ha cambiado necesito ejecutar el comando. Soy realmente nuevo en scripts de bash y no estoy realmente seguro de lo que estoy haciendo, así que no me molestes. También estoy en un Mac, no en Linux. Cualquier puntero o recurso externo sería de gran ayuda. Sé que mucha gente lo prueba en Internet y nadie puede hacerlo bien. Realmente estoy tratando de imitar la funcionalidad de reloj de SASS.
#!/bin/bash
#./watch.sh $PATH $COMMAND
DIR=$1
ls -l $DIR > $DIR/.begin
#this does not work
DIFFERENCE=$(diff .begin .end)
if [ $DIFFERENCE = ''/n'']; then
#files are same
else
$2
fi
ls -l $DIR > $DIR/.end
¿Por qué no usar AppleScript?
http://www.tuaw.com/2009/03/26/applescript-exploring-the-power-of-folder-actions-part-iii/
on adding folder items to this_folder after receiving added_items
tell application "Finder"
...
Aquí hay un ejemplo de ver una carpeta de cambios y ejecutar menos compilador cuando se actualiza. Como requisito previo necesita npm
y estos el módulo onchange . La comunidad de nodos tiene un montón de diferentes comandos de vigilancia (como onchange). No conozco ninguno que sea compilado binarios independientes.
npm install less onchange -g
Entonces puedes usar algo como:
onchange "./stylesheets/*.less" -- lessc main.less > main.css
Prefiero un comando BASH sobre la respuesta Grunt que di hace un tiempo.
Aquí hay una plantilla con la que trabajar, comprobará cada 120 segundos los cambios en el directorio pasado y notificará la creación de directorios, archivos o nombres de canalizaciones. Si también desea ejecutar comandos cuando se elimina algo, verifique mi otra respuesta en para obtener ejemplos adicionales de bucle.
#!/usr/bin/env bash
Var_dir="${1:-/tmp}"
Var_diff_sleep="${2:-120}"
Var_diff_opts="--suppress-common-lines"
Func_parse_diff(){
_added="$(grep -E ''>'' <<<"${@}")"
if [ "${#_added}" != "0" ]; then
mapfile -t _added_list <<<"${_added//> /}"
_let _index=0
until [ "${#_added_list[@]}" = "${_index}" ]; do
_path_to_check="${Var_dir}/${_added_list[${_index}]}"
if [ -f "${_path_to_check}" ]; then
echo "# File: ${_path_to_check}"
elif [ -d "${_path_to_check}" ]; then
echo "# Directory: ${_path_to_check}"
if [ -p "${_path_to_check}" ]; then
echo "# Pipe: ${_path_to_check}"
fi
let _index++
done
unset _index
fi
}
Func_watch_bulk_dir(){
_current_listing=""
while [ -d "${Var_dir}" ]; do
_new_listing="$(ls "${Var_dir}")"
_diff_listing="$(diff ${Var_dec_diff_opts} <(${Var_echo} "${_current_listing}") <(${Var_echo} "${_new_listing}"))"
if [ "${_diff_listing}" != "0" ]; then
Func_parse_diff "${_diff_listing}"
fi
_current_listing="${_new_listing}"
sleep ${Var_diff_sleep}
done
}
Indique si reemplaza las líneas de echo
anteriores con eval <some command>
para cada tipo de acción monitoreada, ya que estará más cerca de la automatización de las acciones. Y si desea ver lo que se ve arriba cuando se usa dentro de un script, entonces revise la última versión de script para el proyecto en el que he estado trabajando para la automatización del cifrado y descifrado a través de gpg y tar.
Casi 3 años después y recomendaría esta solución basada en ronco.
Creé un ejemplo de trabajo aquí https://github.com/reggi/watch-execute .
Aquí está el Gruntfile.js
:
module.exports = function (grunt) {
grunt.initConfig({
shell: {
run_file:{
command: ''sh ./bash.sh'',
options: {
stdout: true
}
}
},
watch: {
run_file: {
files: ["./watchme/*"],
tasks: ["shell:run_file"]
}
}
});
grunt.loadNpmTasks(''grunt-contrib-watch'');
grunt.loadNpmTasks(''grunt-shell'');
};
En Mac OS X, puede hacer clic con el botón derecho en una carpeta y luego hacer clic en "Configuración de las acciones de la carpeta". Esto le permitirá adjuntar acciones a una carpeta, es decir, scripts para ejecutar.
OS X viene con una serie de scripts precompilados, o puede crear uno propio.
Escribí una utilidad general llamada watchfile
para simplificar este tipo de operaciones.
Es menos poderoso que inotifywatch
, pero prefiero una utilidad más simple y menos detallada.
Para la tarea deseada, desea controlar si se han modificado los archivos en el directorio actual. Para enumerar todos los archivos recursivamente en el directorio actual:
find . -type f
Para generar la información de marca de tiempo de cada uno de estos archivos:
find . -type f -print0 | xargs -0 stat
Ahora, puede monitorear esta salida con la utilidad watchfile
y ejecutar un comando CMD
cuando esta información cambie:
watchfile -s "find . -type f -print0 | xargs -0 stat" -e CMD
No puedo creer que nadie haya publicado esto todavía.
Primero asegúrese inotify-tools
estén instaladas.
Entonces úsalos así:
logOfChanges="/tmp/changes.log.csv" # Set your file name here.
# Lock and load
inotifywait -mrcq $DIR > "$logOfChanges" &
IN_PID=$$
# Do your stuff here
...
# Kill and analyze
kill $IN_PID
cat "$logOfChanges" | while read entry; do
# Split your CSV, but beware that file names may contain spaces too.
# Just look up how to parse CSV with bash. :)
path=...
event=...
... # Other stuff like time stamps?
# Depending on the event…
case "$event" in
SOME_EVENT) myHandlingCode path ;;
...
*) myDefaultHandlingCode path ;;
done
Alternativamente, usar --format
lugar de -c
en inotifywait
sería una idea.
Simplemente el man inotifywait
y el man inotifywatch
para obtener más información.
Para supervisar de forma continua la carpeta (md5) y ejecutar un comando en el cambio:
daemon() {
chsum1=""
while [[ true ]]
do
chsum2=`find src/ -type f -exec md5 {} /;`
if [[ $chsum1 != $chsum2 ]] ; then
compile
chsum1=$chsum2
fi
sleep 2
done
}
Funciona en mi sistema operativo X ya que no tengo digest
.
En Linux, puede usar md5sum
como reemplazo del comando md5
.
Si solo necesita verificar los archivos que se crean / eliminan en el nivel superior (sin consultar las subcarpetas), es posible que desee utilizar lo siguiente.
Utiliza pocos recursos, por lo tanto, puede reaccionar rápidamente, lo uso para buscar un archivo modificado.
#!/bin/bash
file="$1"
shift
tmp=$(mktemp)
trap ''rm "$tmp"'' EXIT
while true; do
while [ ! "$tmp" -ot "$file" ]; do
sleep 0.5
done
eval "$@ &"
echo $! > "$tmp"
wait
done
probablemente la forma más rápida de hacerlo ... (en 1G git repo, regresa por debajo de 1 segundo)
#!/bin/bash
watch() {
echo watching folder $1/ every $2 secs.
while [[ true ]]
do
files=`find $1 -type f -mtime -$2s`
if [[ $files == "" ]] ; then
echo "nothing changed"
else
echo changed, $files
fi
sleep $2
done
}
watch folder 3
MÉTODO 1:
#!/bin/sh
check() {
dir="$1"
chsum1=`digest -a md5 $dir | awk ''{print $1}''`
chsum2=$chsum1
while [ $chsum1 -eq $chsum2 ]
do
sleep 10
chsum2=`digest -a md5 $dir | awk ''{print $1}''`
done
eval $2
}
check $*
Este script toma dos parámetros [directorio, comando]. Cada 10 segundos, el script ejecuta check()
para ver que la carpeta ha cambiado. Si no, duerme y el ciclo se repite.
En el caso de que la carpeta haya cambiado, eval
su comando.
MÉTODO 2:
Use un cron para monitorear la carpeta.
Tendrás que instalar incron:
sudo apt-get install incron
Y entonces tu script se verá más o menos así:
#!/bin/bash
eval $1
(No será necesario que especifique la carpeta, ya que el trabajo del cron consistirá en supervisar el directorio especificado)
Un ejemplo completo y funcional se puede encontrar aquí:
#!/bin/bash
# Author: Devonte
# NGINX WATCH DAEMON
# Place file in root of nginx folder /etc/nginx
# This will test your nginx config on any change and
# if there are no problems it will reload your configuration
# USAGE: sh nginx-watch.sh
dir=`dirname $0`
checksum_initial=`tar -cf - $dir | md5sum | awk ''{print $1}''`
checksum_now=$checksum_initial
# Start nginx
nginx
while true
do
sleep 3
checksum_now=`tar -cf - $dir | md5sum | awk ''{print $1}''`
if [ $checksum_initial != $checksum_now ]; then
echo "[ NGINX ] A configuration file changed. Reloading..."
nginx -t && nginx -s reload;
fi
checksum_initial=$checksum_now
done