Skip to content

Instantly share code, notes, and snippets.

@koepnick
Last active July 18, 2024 22:07
Show Gist options
  • Save koepnick/d7c16a72e065b77807d0318f4ddb72bb to your computer and use it in GitHub Desktop.
Save koepnick/d7c16a72e065b77807d0318f4ddb72bb to your computer and use it in GitHub Desktop.
Simple monitoring script using inotify

I wanted to be able to call a simple script from the console or Neovim that would supply an executable and an arbitrary number of files.

Using inotify, each file is monitored for changes; calling the executable when one is detected. The executable is implicitly watched.

This is a very quick and dirty solution. It uses eval and doesn't perform any sanity checking. Nor does it check to see if watches are already in place. Use at your own risk.

In my own setup, I have a '~/.local/scripts/' directory which is on my $PATH. I have the script here named 'monitor'

Usage: $> monitor ./something_neat.py ./some_config.yaml ./pyproject.toml /var/tmp/something.png

This will run './something_neat.py' whenever './something_neat.py', './some_config.yaml', './pyproject.toml', or '/var/tmp/something.png' changes.

Easy install: $> curl https://gist.githubusercontent.com/koepnick/d7c16a72e065b77807d0318f4ddb72bb/raw/df7f9115858c5b82aee6606387416a111829ed49/monitor.sh -o $PATH/.local/scripts/monitor

#!/bin/bash
executable=$(realpath "${1}")
targets=${@}
max_watches=$(cat /proc/sys/fs/inotify/max_user_watches)
echo "--------------------------------------------------"
echo "Targets: ${targets}"
echo "Will execute: ${executable} on change"
echo "--------------------------------------------------"
echo "The user has a maximum of ${max_watches} inotify watches"
echo " This can be configured by adding:"
echo " fs.inotify.max_user_watches=n"
echo " to /etc/sysctl.conf and running"
echo " $> sysctl --load"
echo "--------------------------------------------------"
function mon() {
inotifywait -m \
-e close_write \
--include "${1}" \
$(dirname ${1}) |
while read data
do
eval "${executable}"
done
}
# Iterate through all of our parameters
for i in "${@}"
do
# Exclude the executable file. It will be the
# last file monitored and will not be backgrounded
# This is to ensure that when this script is exited,
# all other inotifywait instances launched from here
# will exit as well.
realpath=$(realpath "${i}")
if [[ "${realpath}" != "${executable}" ]]
then
mon $realpath &
fi
done
mon $executable
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment