Monitor Folder Contents with launchd - Including Subfolders?
I want to make a shell script that runs any time the contents of a particular folder on my server are changed. Seems easy enough at first, because launchd
has a directive called WatchPaths
which triggers your script any time the contents of a folder change.
HOWEVER WatchPaths
is not triggered by changes in subfolders. The folder I'm trying to watch is a few hundred MB of small web files, nested several levels deep in sub folders. Far too many folders to try to manually list each one.
Is there some other sane way to accomplish this?
Solution 1:
WatchPaths
doesn't appear to be able to watch a sub-directory recursively, so the best you can do with it is watch a single directory's activities. You might want to take a look at Folder Actions, they're discussed in detail in this blog post titled: Setup OS X Folder Actions to Know When a File is Added as well.
Another alternative is to use a CLI tool that's available in Homebrew via the brew install fswatch
command. fswatch
is a cross platform implementation that works on most flavors of *NIX includes macOS.
The FSEvents monitor, available only on OS X, has no known limitations, and scales very well with the number of files being observed.
Example
Here I've created a sub-directory called ~/somedir
. I then invoked `fswatch against this directory:
$ mkdir ~/somedir
$ fswatch /some/dir
Now if we start adding files and sub-directories fswatch
will notify:
$ touch ~/somedir/afile
fwatch msg>> /Users/joeuser/somedir/afile
$ mkdir ~/somedir/anotherdir
fswatch msg>> /Users/joeuser/somedir/anotherdir
$ touch ~/somedir/anotherdir/afile
fswatch msg>> /Users/joeuser/somedir/anotherdir/afile
The above can be adapted for use in a shell script which can take whatever other actions you require when any changes are detected against the directory tree that fswatch
is monitoring.
Other Examples
To act on file system activity you can use one of these 2 patterns:
$ fswatch -0 path | while read -d "" event \
do \
// do something with ${event}
done
Or this:
$ fswatch -o path | xargs -n1 -I{} program