I'm rather reusing existing stuff but seeing how every scriptable filesystem watcher misses the point, I'm inclined to write my own inotifywait/inotifywatch wrapper.
I'm rather reusing existing stuff but seeing how every scriptable filesystem watcher misses the point, I'm inclined to write my own inotifywait/inotifywatch wrapper.
mkdir /tmp/project
cd /tmp/project
touch file{1,2}
ls | entr -d echo "a change"
Terminal 2: rm file2
Terminal 1: entr: cannot open 'file2': No child processes
Regarding `-d`:> Track the directories of regular files provided as input and exit if a new file is added. This option also enables directories to be specified explicitly. Files with names beginning with ‘.’ are ignored.
So first, it doesn't track NEW directories, and second, it exits if new file is added. Exactly how is this useful?
EDIT: All I want from filesystem watcher is to track files by pattern and just re-run the command, however complex that may be to implement via OS interfaces. When I'm working on a Python project that has packages (directories), I may also refactor (rename files), and this simplistic behavior does not catch that.
I've had good luck with modd: https://github.com/cortesi/modd/
I just tested exactly what you described, did not see any errors, and it ran my commands exactly the way I wanted.
I would also like to extol virtues of its sister project devd[0] from same author which makes web development palatable to me. It's a little websocker server that injects a tiny script into HTML to reload the page in browser once modd detects file change, rebuilds front-end and sends devd a SIGHUP.
$ while true; do
> ls -d src/*.py | entr -d ./setup.py
> done
that way when a file/dir is added/removed it restarts Rebuild project if a source file is modified or added to the src/ directory:
$ while true; do ls src/*.rb | entr -d make; doneI assume I'm misunderstanding something, so this is probably a naive question and maybe you can explain further, but if that is all you need why not just write it yourself? It sounds like an <1 hour project to write something cross-platform in Qt that monitors the filesystem recursively with QFileSystemWatcher https://doc.qt.io/qt-5/qfilesystemwatcher.html checks for the configured regexen and runs the configured command.
- Multiple files may change in quick succession, for example, if you hit “save all” in an editor. You might want to delay triggers to see if more events arrive.
- You will sometimes see incomplete / corrupted versions of files, because you ran a command while another program was writing the file. The other program probably should atomically rewrite the file, but you’re stuck fixing the problem. The user doesn’t want to see errors from this and you generally want to rerun the command.
- You need to execute commands in the correct order.
- A command may change state from being queued&ready to having outdated inputs.
If it’s just one command, sure, you could probably do it in an hour. But if there’s more than one command (usually the case!) then it gets far more complicated.
Just looking at the last time I implemented something like this--it was watchman + about 500 lines of code figuring out which actions to run and when. And that’s not even with any parallel execution.
A more technical description is mentioned here: https://github.com/fsnotify/fsnotify/issues/18
inotifywait -rq -m -e close_write --format %f . | grep '\.rules$'
Sure, there may races due to limitations of underlying OS interfaces, but no such races really matter when you edit with mammal speed, so it's perfectly sufficient, and so it is perfectly possible to make good file system watcher, without any user-space power-hungry hacks.In fact it's man page comes with a big fat warning about using -r:
> Warning: If you use this option while watching the root directory of a large tree, it may take quite a while until all inotify watches are established, and events will not be received in this time. Also, since one inotify watch will be established per subdirectory, it is possible that the maximum amount of inotify watches per user will be reached. The default maximum is 8192; it can be increased by writing to /proc/sys/fs/inotify/max_user_watches.
(ref: https://linux.die.net/man/1/inotifywait)
Really what would be nice would be for Linux to support this natively so we don't have to resort to dirty hacks.
What problem?
What you quoted is totally irrelevant for my workflow. On my crappy laptop and all projects in my work directory, the watches are established almost instantly, without any spike in CPU.
There are 4677 directories in Linux kernel and you can just put a knob change in /etc/sysctl.d/ if your code base is bigger than kernel.
You're just inventing OS limitations to justify limitations of lazy user-space programming.
EDIT: Setting up watches on kernel tree including directories in .git:
~/src/linux % inotifywait -r -m -e close_write --format %f . |& ts
Jul 01 16:03:10 Setting up watches. Beware: since -r was given, this may take a while!
Jul 01 16:03:10 Watches established.
Less than 1 second. Big deal!FYI: What OS interface do you think that `entr` uses on Linux? That's right, inotify.
This allows software like Voidtool's Everything to index the entire filesystem and update that index in real time. Using inotify for that is not possible since you'd have to recursively register for hunderds of thousands of directories, which far exceeds the limit of allowed registerations (and either way, would be quite wasteful to hold 100,000 registration handles). As a result, the Linux equivalent to Everything is unable to find recently created files, erronously finds deleted files and has outdated metadata fo recently changed files. Alternatively, you can attempt to reindex right before searching (e.g. rerun updatedb if you are using locate), but then your searches are much slower and the benefit of indexing for a quick search is reduced significantly.
A nicer API would allow to use one registration handle to get notifications for an entire directory tree or at least have a seprate API for an entire filesystem (like the NTFS option mentioned above).
At least, that was the conclusion I came to when I last researched the topic. If you know of a supported way of doing this on Linux I'd really love to know! It will allow me to finally make the program I wanted to make!
Have you heard of https://www.man7.org/linux/man-pages/man7/fanotify.7.html ? This doesn't require watches on individual directories. Though:
> Calling fanotify_init() requires the CAP_SYS_ADMIN capability.
inotifywait -rq -m -e close_write --format %f --exclude .git | grep '\.rules$' | debounce 1 | xargs ... `while inotifywait -q -q -r -e modify -e move -e create -e delete --exclude '[*~#]' $(mapi $wd $@); do`
wd is the working directory.and mapi
my $prefix=shift;
foreach my $s (@ARGV) {
print "$prefix/$s ";
}
Adjust to taste.it is _hax_, as it were. but it has worked well for me.
[1] - http://gittup.org/tup/
There's no way I'm going to invoke node.js and associated `node_modules` with 1:10 code to junk ratio, for a any CLI scripting.