watchmedo

File system watcher from Python’s watchdog. Run commands when files change (auto-restart, rebuild, sync, etc.).

Category: Development / Ops Filesystem events Automation Python watchdog Hot reload

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 event
    • watchmedo 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}"' /etc

Notes & Gotchas

  • Inotify limits (Linux): watching many files may hit max watches. Tune fs.inotify.max_user_watches.
  • Recursive watching: use --recursive for 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)