inotifywait is a handy utility that listens for filesystem events you specify
and prints them to standard out. This is particularly useful if, say, you want
to automatically redeploy a website whenever something changes.
(Jekyll comes with this functionality out-of-the-box, but if you have more than one site, or other non-Jekyll content that changes, it may be desirable to deploy everything together.)
The naive approach to this problem might look something like:
# Filesystem events specific to file creation or modification events="modify,attrib,close_write,move,create,delete" # -m = monitor (don’t quit after the first event) # -r = recursive inotifywait -m -r -e "$events" $site_dir | while read ; do deploy_site ; done
But the problem with filesystem events is that lots of them can fire simultaneously. A single file save produces multiple events, and a project-wide find/replace opens the floodgates. Since the site will deploy on every individual event, even minor changes kick off 3-4 rebuilds in a row. That’s pretty silly.
I found a few patterns out on the ’net to batch
inotifywait messages, but most
of them were pretty complicated. I
wondered if it might be possible to do the same thing in a more straightforward
fashion, and came up with this:
echo "Watching source directory for changes." events="modify,attrib,close_write,move,create,delete" while true do count=0 while read -t 1 do (( count++ )) done if [[ $count -gt 0 ]] then echo "$count changes detected." deploy_site fi done < <(inotifywait -m -r -e "$events" --exclude '/\..+' $dir 2>/dev/null)
As it turns out,
read accepts a timeout value! Now any inotify events less
than a second apart will be counted as part of the same batch and will result in
only a single
A word of warning: failure to exclude
.git folders will result in a ton of
filesystem events. In the above code, I ignore all dotfiles (and folders) to
avoid this problem.