home ~ projects ~ socials

Automatically Run Any File That Changes With watchexec

watchexec is a great little tool for running a specific process when certain files change. For example, I use it to trigger a rebuild of my site when content changes. I also use it to automatically run individual scripts I'm working on with a command like this:

watchexec --project-origin . -w ping.py ./ping.py

That command watches a file named "ping.py" in the current directory and runs it whenever it changes.

It's a bit of a pain to set that up each time. I wrote this bash script to handle automatically running any script in a directory when it changes.

script-runner.bash

#!/bin/bash

watchexec \
--project-origin . \
--debounce 100 \
--exts .rs \
--exts .py \
--emit-events-to json-stdin \
--fs-events 'modify' \
'jq ".tags[] | select(.kind == \"path\") | .absolute" | xargs bash -c'

Details

Notes

  • watchexec is the main process that detects file changes
  • --project-origin . sets up to watch the current directory. It seems like this shouldn't be necessary but I get weird behavior sometimes without it
  • --debounce 100 tries to limit the events a little, but it doesn't work the way I expect and sometimes multiple events still show up even with larger values. I'm leaving it here for now as a type of work in progress to dig into more if things become an issue (which hasn't been a problem to date)
  • The --exts arguments set the file extensions the process watches for. Here I'm doing ".rs" and ".py" for my rust and python scripts
  • The --emit-events-to json-stdin argument sends notifications out as JSON along STDIN. I use this to find the filepath of the file that changed with jq so I know what to run
  • Using --fs-events 'modify' limits the file events to only when files are modified. Without, lots of extra events for metadata changes show up too
  • The jq command parses the payload from watchexec to grab the path of the file that changed. It's then send to xargs that calls it as an argument to bash -c which results in running the script

Usage

I put that code in script in my one-off script scratchpad directory. Running it lets me work on any of the scripts and seeing them run automatically every time I save changes.

-- end of line --

References