Skip to content

Instantly share code, notes, and snippets.

@davesque
Created September 18, 2019 18:39
Show Gist options
  • Save davesque/b5cd54c333d5a17211ef0d5a967a704b to your computer and use it in GitHub Desktop.
Save davesque/b5cd54c333d5a17211ef0d5a967a704b to your computer and use it in GitHub Desktop.
Portable file watcher in bash.
#!/usr/bin/env bash
_usage() {
printf 'usage: %s [-p|--poll <sec per poll>] [-a|--all] [<find args>] -- <command> [<args>]\n' "$(basename "$0")" >&2
exit 64
}
# Default arg values
sec_per_poll=2
find_all=false
find_args=()
# Parse args
while [[ "$1" != '--' ]]; do
case "$1" in
-p|--poll)
shift
sec_per_poll=$1 ;;
-a|--all)
find_all=true ;;
*)
find_args+=("$1") ;;
esac
# Print usage if end of arguments encountered before '--'
shift || _usage
done
# Shift past '--'
shift
if $find_all; then
_my_find() {
find . "$@" -print0
}
else
_my_find() {
find * "$@" -print0
}
fi
if [[ $(uname) == Darwin ]]; then
_find_and_hash() {
_my_find "$@" | xargs -0 -n 100 stat -f'%m' | cksum
}
else
_find_and_hash() {
_my_find "$@" | xargs -0 -n 100 stat -c'%y' | cksum
}
fi
# Print usage if no find args were given
if [[ -z "${find_args[*]}" ]]; then
_usage
fi
# Poll for changes every $sec_per_poll seconds
prev_hash=
while true; do
curr_hash=$(_find_and_hash "${find_args[@]}")
if [[ $prev_hash != $curr_hash ]]; then
printf '[%s] Changes detected in files...\n' "$(date)" >&2
# Execute specified command
"$@" || printf 'Command exited with status %d\n' $? >&2
prev_hash=$curr_hash
fi
sleep $sec_per_poll
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment