ExecuteCommandOnFileChange

24th April 2017 at 2:06pm
bash inotify TechnicalNotes

Use the inotify-tools package.

inotifywait -m -e create --format '%w%f' $(find /my/path/ -type d) \
  | while read -r newfile ; do
  echo "new file: '$newfile'"
done

https://superuser.com/questions/181517/how-to-execute-a-command-whenever-a-file-changes

Simple, using inotifywait (install your distribution's inotify-tools package):

while inotifywait -e close_write myfile.py; do ./myfile.py; done

or

inotifywait -q -m -e close_write myfile.py |
while read -r filename event; do
  ./myfile.py         # or "./$filename"
done

The first snippet is simpler, but it has a significant downside: it will miss changes performed while inotifywait isn't running (in particular while myfile is running). The second snippet doesn't have this defect. However, beware that it assumes that the file name doesn't contain whitespace. If that's a problem, use the –format option to change the output to not include the file name:

inotifywait -q -m -e close_write --format %e myfile.py |
while read events; do
  ./myfile.py
done

Either way, there is a limitation: if some program replaces myfile.py with a different file, rather than writing to the existing myfile, inotifywait will die. Many editors work that way.

To overcome this limitation, use inotifywait on the directory:

inotifywait -e close_write,moved_to,create  . |
while read -r directory events filename; do
  if [ "$filename" = "myfile.py" ]; then
    ./myfile.py
  fi
done

Alternatively, use another tool that uses the same underlying functionality, such as incron (lets you register events when a file is modified) or fswatch (a tool that also works on many other Unix variants, using each variant's analog of Linux's inotify).


Related