What it does
watchmedo is a CLI tool shipped with the Python watchdog package. It watches one or more directories for file system events (create/modify/delete/move), and triggers actions like running a command or restarting a process.
# Install (common patterns) python3 -m pip install --user watchdog # or on some distros: pipx install watchdog
How it works (mechanical)
- Uses OS-level event systems when available (Linux: inotify, macOS: FSEvents, Windows: ReadDirectoryChangesW).
- Falls back to polling in some scenarios (slower, more CPU).
- Two most-used subcommands:
watchmedo shell-command— run a command per eventwatchmedo auto-restart— restart a long-running command on changes
- Patterns control what files trigger events (include/exclude).
10 Practical Examples
# 1) Auto-restart a Python app when *.py changes watchmedo auto-restart --patterns="*.py" --recursive -- python3 app.py
# 2) Auto-restart a service wrapper script when configs change watchmedo auto-restart --patterns="*.conf;*.ini" --recursive -- ./run-service.sh
# 3) Run a build when source changes watchmedo shell-command --patterns="*.c;*.h" --recursive --command='make -j && echo "build ok"' .
# 4) Re-generate your Clarus HTML index when pages change (example) watchmedo shell-command --patterns="*_guide-clarus.html" --recursive --command='python3 build-index.py' /path/to/library
# 5) Watch a log directory and trigger a summarizer on new files
watchmedo shell-command --patterns="*.log" --recursive --command='echo "new log: ${watch_src_path}"' /var/log# 6) Sync changed files to another host (rsync on change) watchmedo shell-command --patterns="*.html;*.css" --recursive --command='rsync -av --delete ./ user@host:/srv/www/' .
# 7) Only react to certain events (modified)
watchmedo shell-command --patterns="*.txt" --recursive --command='echo "modified: ${watch_src_path}"' --event-modified .# 8) Ignore noisy folders (like .git or node_modules) watchmedo auto-restart --patterns="*.py" --ignore-patterns=".git/*;node_modules/*" --recursive -- python3 app.py
# 9) Watch a single file and run a command when it changes (via its folder + pattern) watchmedo shell-command --patterns="nginx.conf" --command='nginx -t && systemctl reload nginx' /etc/nginx
# 10) Quick “ops guardrail”: alert when a critical file changes
watchmedo shell-command --patterns="fstab" --command='logger -p authpriv.notice "fstab changed: ${watch_src_path}"' /etcNotes & Gotchas
- Inotify limits (Linux): watching many files may hit max watches. Tune
fs.inotify.max_user_watches. - Recursive watching: use
--recursivefor directory trees, but it increases watch count. - Quoting: shell quoting inside
--command='...'can get tricky; test in a simple directory first. - Auto-restart loops: if your command writes into the watched folder, you can create restart storms. Exclude output dirs.
- Polling fallback: on some network file systems, event support may be limited → watchmedo may behave like polling.
Historical Context
Before ubiquitous hot-reload workflows, developers used make, manual restarts,
or OS-specific tools. watchdog + watchmedo unified cross-platform file watching into a simple Python package and CLI.
Modern Equivalent
Depending on the stack, alternatives include:
- entr (simple stdin-based watcher),
- inotifywait (Linux-only, very direct),
- language-specific watchers (nodemon, cargo watch, reflex, etc.).
watchmedo stays valuable when you want a cross-platform watcher with predictable CLI behavior.
Related Commands
- inotifywait — Linux inotify watcher (inotify-tools)
- entr — simple watcher triggered by stdin list
- systemd.path — systemd unit that triggers on filesystem changes
- watch — run a command repeatedly on an interval (not event-driven)