watfs
I want to run a command, every time a file in a directory changes. Some directories need to be ignored. New directories should be watched too. Simple, i’ll just use…
inotifywait
inotifywait efficiently waits for changes to files using Linux’s inotify(7) interface. It is suitable for waiting for changes to files from shell scripts. It can either exit once an event occurs, or continually execute and output events as they occur. - inotifywait man page
To run a command every time a file changes, one would need the following script:
while inotifywait --recursive ./*; do echo "do things"; doneRunning this and making a change, i see the following:
$ while inotifywait --recursive ./*; do echo "do things"; done
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.
./content/projects/ MOVED_FROM watfs.md
do things
Setting up watches. Beware: since -r was given, this may take a while!
Watches established.Oh, i see, this sets up the watches again everytime it detects a change. Well that’s not very efficient. Let’s try using a pipe instead of a loop.
inotifywait -qmr ./* | while read; do echo "do things"; doneRunning this and making a change, i see the following:
$ inotifywait -qmr ./* | while read; do echo "do things"; done
do things
do things
do things
do things
do things
do things
do things
do thingsThat’s not very efficient either. Why does it run so many times for a single change? Let’s see the output of inotifywait directly.
$ inotifywait -qmr ./*
./content/projects/ MOVED_FROM watfs.md
./content/projects/ MOVED_TO watfs.md9j639W.bck
./content/projects/ CREATE watfs.md
./content/projects/ OPEN watfs.md
./content/projects/ MODIFY watfs.md
./content/projects/ CLOSE_WRITE,CLOSE watfs.md
./content/projects/ ATTRIB watfs.md
./content/projects/ DELETE watfs.md9j639W.bckAh, i heard of this behaviour. Editors often move the original file away and create a new one. So using inotifywait for my use case is not very fun. I want something that groups events together.
Let’s try…
watchexec
watchexec has over 370 dependencies and accepts contributions from LLMs (already has 3 from claude).
This bothers me. It’s great, but i don’t want to use it, so let’s try…
entr
entr needs a list of files to watch, and doesn’t watch new directories, so that’s not going to work either.
Fuck it, let’s write my own. I present to you:
watfs
watfs watches directories and runs a command every time a file changes.
watfs does not include code generated by LLMs. This includes the dependencies1. It has 6 dependencies in total, 2 directly: inotify on linux-like systems and kqueue on bsd-like systems. watfs groups events together based on time (debouncing), by default 200ms, adds new directories to the watchlist, and ignores hidden files and directories.
To run cargo check every time something in a rust project changes, simply do:
watfs -i target -- cargo checkCurrently only systems with inotify are supported, but support for kqueue systems is planned. I also intend to add support for .gitignore/.ignore files.
watfs is in the public domain, free to use and not well tested. To install it, you currently must have the rust toolchain installed and build it from source using:
cargo install --locked --git https://codeberg.org/chjlsch/watfs.gitIf you’re up to it, i would appreciate if you’d install and use it, in the hopes of encountering bugs and edge cases. If you find bugs or have a problem, idea, question or feedback, don’t hesitate to open an issue on codeberg. It’s hard to verify this, but i tried my best. Open an issue if you find something i missed. ↩