Using Inotify in a Script to Monitor a Directory

How to continuously monitor the directory using dnotify /inotify command

Inotify itself is a kernel module accesible via calls from e.g. a C program.

https://linux.die.net/man/7/inotify

There is an application suite called inotify-tools, which contains:

inotifywait - wait for changes to files using inotify

http://linux.die.net/man/1/inotifywait

and

inotifywatch - gather filesystem access statistics using inotify

http://linux.die.net/man/1/inotifywatch

You can use inotify directly from command line, e.g. like this to continuously monitor for all changes under home directory (may generate lots of output):

inotifywait -r -m $HOME

And here is a script that monitors continuously and reacts to Apache log activity, copied from the man file of inotifywait:

#!/bin/sh
while inotifywait -e modify /var/log/messages; do
if tail -n1 /var/log/messages | grep httpd; then
kdialog --msgbox "Apache needs love!"
fi
done

Using inotify in a script to monitor a directory

It turns out all I had to do was pipe the command into a while loop:

!/bin/sh

inotifywait -mqr -e close_write "/root/secondfolder/" | while read line
do
echo "close_write"
done

How to use inotifywait to wait till a file is created and is written content with timeout

You cannot wait for ./hello.txt because it doesn't exist yet, so the kernel has no node to attach the inotify object to.

You need to wait on the parent directory (.).
The problem is that you have to find a way to filter out only the specific file.
If you have at least version 3.20.1 of inotifywait, you can just use the option --include to pass a regex with the name of your file.
If you don't, ...well, you can try to use the option --exclude and write a reversed regex or you can write a script to filter the result externaly. Both of these options are rather inconvenient.
Answers to this question describe various ways of making the filter: https://unix.stackexchange.com/q/323901/133542.

If you have the new version, the command will look like this:

inotifywait -e close_write -t 30 --include 'hello\.txt' .

A few remarks:

  • Flags -m and -t are not allowed together (at least in my version). However, you're waiting for a single specific event so there is no need for -m.
  • In your code, you're waiting for the event create but you've stated that you want to know when the file is written. I've changed the event to close_write which means that the file is being closed after being opened in writable mode.
  • The flag --fromfile means that the file contains a list of files to be watched, not that it is being watched itself. I've removed the flag.
  • The flag -r is necessary only if you want to watch an entire tree of directories. If the file is directly in the watched directory, you don't need it.

Monitor Pre-existing and new files in a directory with bash

Once inotifywait is up and waiting, it will print the message Watches established. to standard error. So you need to go through existing files after that point.

So, one approach is to write something that will process standard error, and when it sees that message, lists all the existing files. You can wrap that functionality in a function for convenience:

function list-existing-and-follow-modify() {
local path="$1"
inotifywait --monitor \
--event modify \
--format %f \
-- \
"$path" \
2> >( while IFS= read -r line ; do
printf '%s\n' "$line" >&2
if [[ "$line" = 'Watches established.' ]] ; then
for file in "$path"/* ; do
if [[ -e "$file" ]] ; then
basename "$file"
fi
done
break
fi
done
cat >&2
)
}

and then write:

list-existing-and-follow-modify "$path" \
| while IFS= read -r file
# ... work on/with "$file"
# move "$file" to a new directory
done

Notes:

  • If you're not familiar with the >(...) notation that I used, it's called "process substitution"; see https://www.gnu.org/software/bash/manual/bash.html#Process-Substitution for details.
  • The above will now have the opposite race condition from your original one: if a file is created shortly after inotifywait starts up, then list-existing-and-follow-modify may list it twice. But you can easily handle that inside your while-loop by using if [[ -e "$file" ]] to make sure the file still exists before you operate on it.
  • I'm a bit skeptical that your inotifywait options are really quite what you want; modify, in particular, seems like the wrong event. But I'm sure you can adjust them as needed. The only change I've made above, other than switching to long options for clarity/explicitly and adding -- for robustness, is to add --format %f so that you get the filenames without extraneous details.
  • There doesn't seem to be any way to tell inotifywait to use a separator other than newlines, so, I just rolled with that. Make sure to avoid filenames that include newlines.


Related Topics



Leave a reply



Submit