Last active
April 30, 2025 13:49
-
-
Save mherkazandjian/2f3e6cb658db86f4eb948b9249f110d4 to your computer and use it in GitHub Desktop.
script for watching content and executing arbitrary commands when changes are detected
This file contains hidden or 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 | |
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