- 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...>
Last active
June 8, 2023 15:56
-
-
Save thiagoh/5d8f53bfb64985b94e5bc8b3844dba55 to your computer and use it in GitHub Desktop.
watchfiles: Watch multiple files and execute bash commands as file changes occur
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment