watchfiles
- author: Thiago Andrade thiagoh@gmail.com
- license: GPLv3
- description:
- watches the given paths for changes
- and executes a given command when changes occur
- usage:
- watchfiles <paths...>
If you want to make watchfiles
globally accessible on your environment execute the following instructions:
$ # clone this gist
$ git clone https://gist.github.com/5d8f53bfb64985b94e5bc8b3844dba55.git
$ cd 5d8f53bfb64985b94e5bc8b3844dba55
$ # give execution mode
$ chmod +x watchfiles
$ # copy to some location visible by your $PATH (/usg/local/bin for example)
$ sudo cp watchfiles /usr/local/bin/watchfiles
#!/bin/bash | |
# script: watchfiles | |
# author: Thiago Andrade <thiagoh@gmail.com> | |
# license: GPLv3 | |
# description: | |
# watches the given paths for changes | |
# and executes a given command when changes occur | |
# usage: | |
# watchfiles <cmd> <paths...> | |
# | |
interval=1 | |
verbose=0 | |
quiet=0 | |
cmd="" | |
error_message="" | |
error=0 | |
print_error() { | |
_error_message=$1 | |
echo "Error: ${_error_message}" 1>&2; | |
} | |
check_error() { | |
if [ $error -eq 1 ]; then | |
print_error "${error_message}"; | |
exit 1; | |
fi | |
} | |
show_help() { | |
echo "Usage: watchfiles [options] command [path1] [path2...]" | |
echo -e " -t --interval\t\tInterval in seconds to wait until next check" | |
echo -e " -q --quiet\t\t\tQuiet" | |
echo -e " -qq --quietquiet\t\tSuper quiet" | |
echo -e " -v --verbose\t\tVerbose (good for debug purposes)" | |
} | |
for i in "$@"; do | |
key="$1" | |
case $key in | |
-v|--verbose) | |
verbose=1 | |
shift | |
;; | |
-q|--quiet) | |
quiet=1 | |
shift # past argument | |
;; | |
-qq|--quietquiet) | |
quiet=2 | |
shift # past argument | |
;; | |
--help) | |
show_help | |
shift # past argument | |
exit 1; | |
;; | |
-t) | |
interval="$2" | |
shift # past -t | |
shift # past value | |
;; | |
--interval=*) | |
interval="${key#*=}" | |
shift # past argument=value | |
;; | |
*) | |
cmd=$key | |
shift | |
break; | |
;; | |
esac | |
done | |
path=$* | |
# echo "interval $interval" | |
# echo "cmd $cmd" | |
# echo "path $path" | |
# echo "verbose $verbose" | |
# echo | |
# echo | |
re='^[0-9]+$' | |
if ! [[ $interval =~ $re ]] ; then | |
error_message="Interval must be an integer" | |
error=1 | |
fi | |
check_error | |
if [ -z "$path" ]; then | |
error_message="No such files"; | |
error=1 | |
fi | |
check_error | |
if [ $verbose -eq 1 ]; then | |
quiet=0 | |
fi | |
update_sha() { | |
_path=$1 | |
current_sha=`ls -lR --time-style=full-iso $_path | sha1sum |rev| cut -d' ' -f2-| rev` | |
echo $current_sha | |
return 0 | |
} | |
check_files() { | |
tmp_path="" | |
counter=0 | |
error_counter=0 | |
for file in $path; do | |
if [ ! -f $file ]; then | |
echo "File ${file} does not exists! Skipping it." 1>&2; | |
((error_counter=error_counter + 1)) | |
else | |
tmp_path="$tmp_path $file" | |
fi | |
((counter=counter + 1)) | |
done | |
if [ $counter -eq $error_counter ]; then | |
error=1 | |
error_message="No such existing or valid files" | |
return 1; | |
fi | |
if [ $counter -eq 0 ]; then | |
error=1 | |
error_message="At least one file is required" | |
return 1; | |
fi | |
path=$tmp_path | |
} | |
compute_all_checksum() { | |
combined_sha="" | |
counter=0 | |
error_counter=0 | |
for i in $path; do | |
file_sha=`update_sha $i` | |
ret=$? | |
# echo $i is $file_sha with return $ret | |
if [ $ret -eq 0 ]; then | |
combined_sha="${combined_sha}${file_sha}" | |
else | |
((error_counter=error_counter + 1)) | |
fi | |
((counter=counter + 1)) | |
done; | |
echo $combined_sha | |
} | |
check_files | |
check_error | |
files_sha=`compute_all_checksum` | |
previous_sha=$files_sha | |
execute_command() { | |
if [ $verbose -eq 1 ]; then | |
echo "Executing command: ${cmd}..." | |
fi | |
/bin/bash -c "$cmd" | |
} | |
compare() { | |
files_sha=`compute_all_checksum` | |
if [[ $files_sha != $previous_sha ]] ; then | |
if [ $quiet -eq 0 ]; then | |
echo -e "\nFile(s) changed" | |
fi | |
execute_command | |
previous_sha=$files_sha | |
else | |
if [ $quiet -lt 2 ]; then | |
echo -n '#' | |
fi | |
fi | |
} | |
trap exit SIGQUIT | |
trap exit SIGINT | |
if [ $quiet -eq 0 ]; then | |
echo -e "## Watching files: ${path}" | |
fi | |
while true; do | |
compare | |
sleep $interval | |
done |