Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mherkazandjian/2f3e6cb658db86f4eb948b9249f110d4 to your computer and use it in GitHub Desktop.
Save mherkazandjian/2f3e6cb658db86f4eb948b9249f110d4 to your computer and use it in GitHub Desktop.
script for watching content and executing arbitrary commands when changes are detected
#!/bin/bash
usage() {
echo "Usage: $0 --watch <path_pattern> --cmd <command>"
echo " Monitors files/directories matching <path_pattern> for close_write events"
echo " and executes <command> upon detection."
echo " The placeholder {} in <command> will be replaced with the full path of the changed file."
echo "Examples:"
echo " $0 --watch 'src/**/*.js' --cmd 'echo \"File {} changed\" && eslint {}'"
echo " $0 --watch '/config/app.conf' --cmd '/bin/bash /opt/scripts/reload_service.sh {}'"
exit 1
}
# Parse command line options
WATCH_PATTERN=""
COMMAND_TO_RUN=""
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
--watch)
WATCH_PATTERN="$2"
shift; shift
;;
--cmd)
COMMAND_TO_RUN="$2"
shift; shift
;;
--help|-h)
usage
;;
*)
echo "Unknown option: $1"
usage
;;
esac
done
if [ -z "$WATCH_PATTERN" ] || [ -z "$COMMAND_TO_RUN" ]; then
echo "Error: --watch and --cmd are required."
usage
fi
# Define function to monitor and execute command for a given path.
watch_and_execute() {
local watch_path="$1"
local command_template="$2"
echo "Watching: $watch_path"
echo "Command: $command_template"
# Ensure the directory exists before watching
if [ ! -e "$watch_path" ]; then
echo "Error: Watch path '$watch_path' does not exist."
return 1
fi
inotifywait -m -r -e close_write --format '%w%f' "${watch_path}" | while read file
do
echo "Detected change in: $file"
# Replace placeholder {} with the filename
local cmd_instance="${command_template//\{\}/$file}"
echo "Executing: $cmd_instance"
# Execute the command. Consider error handling or background execution if needed.
eval "$cmd_instance"
done
}
# Expand watch pattern supporting globs.
# Use eval to handle potential tilde expansion in the pattern
eval "watch_matches=( $WATCH_PATTERN )"
if [ ${#watch_matches[@]} -eq 0 ]; then
echo "Error: No matches found for watch pattern '$WATCH_PATTERN'."
exit 1
fi
# Launch each watch_and_execute function asynchronously.
for path_to_watch in "${watch_matches[@]}"; do
# Check if the matched path exists before launching the watcher
if [ -e "$path_to_watch" ]; then
watch_and_execute "$path_to_watch" "$COMMAND_TO_RUN" &
else
echo "Warning: Matched path '$path_to_watch' does not exist. Skipping."
fi
done
# Wait for all background processes to finish (they won't, as inotifywait runs indefinitely)
# This keeps the main script alive.
wait
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment