32

I want a script to sleep unless a certain file is modifed/deleted (or a file created in a certain directory, or ...). Can this be achieved in some elegant way? The simplest thing that comes to my mind is a loop that sleeps for some time before checking the status again, but maybe there is a more elegant way?

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
Tobias Kienzler
  • 9,184
  • 13
  • 65
  • 106

3 Answers3

34

On linux, you can use the kernel's inotify feature. Tools for scripting can be found there: inotify-tools.

Example use from wiki:

#!/bin/sh

EVENT=$(inotifywait --format '%e' ~/file1) # blocking without looping
[ $? != 0 ] && exit
[ "$EVENT" = "MODIFY" ] && echo 'file modified!'
[ "$EVENT" = "DELETE_SELF" ] && echo 'file deleted!'
# etc...
shellholic
  • 6,215
  • 1
  • 20
  • 15
4

There is an API called inotify for C programmers.

There are some tools that use it, e.g. incron and inotify-tools.

Mikel
  • 56,387
  • 13
  • 130
  • 149
3

Indeed there is: entr(1) will run arbitrary commands when files change, and also provides an auto-reload option for restarting application servers.

edit: some examples

Rebuild if sources files change

$ find *.c | entr make

Launch and auto-reload test server if files change

$ ls *.py | entr -r python main.py

Providing a the agument +/path/to/fifo allows more complex scripting by instructing entr to write the name of each file that changes to a named pipe. The following will convert Markdown files in the current directory to HTML as they're edited

$ ls *.md | entr +/tmp/notify &
$ while read F
> do
>   markdown2html $F
> done < /tmp/notify
eradman
  • 354
  • 1
  • 2
  • 8
  • Intriguing, but weird. So ... it reads a bunch of file names on standard input, and runs the specified command when one of them changes? – tripleee Jul 04 '13 at 05:36
  • Looks interesting, thanks! Is there any way to have `entr` pass on the name of the file that has changed as well? – Tobias Kienzler Jul 04 '13 at 07:00
  • As of the 2.7 release, the special `/_` argument (somewhat analogous to `$`_ in Perl) is replaced with the name of the first file that changed – eradman Dec 06 '14 at 11:50
  • @TobiasKienzler also, maybe you could use `xargs -I % entr %` to pass the file name from the previous pipe of `find *.ext |` or use the special argument as @eradman suggests – alchemy Feb 12 '22 at 22:50