19

I have seen this answer.

You should consider using inotifywait, as an example:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
        # do something with the file
    done

My question is that, the above script watches a directory for creation of files of any type, but how do I modify the inotifywait command to report only when a file of certain type/extension is created (or moved into the directory) - e.g. it should report when any .xml file is created.

WHAT I TRIED:

I have run the inotifywait --help command, and have read the command line options. It has --exclude <pattern> and --excludei <pattern> commands to EXCLUDE files of certain types (by using regEx), but I need a way to INCLUDE just the files of a certain type/extension.

  • BTW, using path above is probably not the best variable name if you want to play with this first in a shell. If you use it, then you will not be able to use commands and everything since this has basically just overridden the standard PATH. Hence I recommend using an alternative var name, like fpath instead. i.e. while read fpath action file then any standard command usually available from your shell will still be. – Baptiste Mathus Oct 9 '18 at 9:17
16

how do I modify the inotifywait command to report only when a file of certain type/extension is created

Please note that this is untested code since I don't have access to inotify right now. But something akin to this ought to work:

inotifywait -m /path -e create -e moved_to |
    while read path action file; do
        if [[ "$file" =~ .*xml$ ]]; then # Does the file end with .xml?
            echo "xml file" # If so, do your thing here!
        fi
    done
  • 2
    This does work and I have tested it with inotifywait. – TheBetterJORT Apr 7 '17 at 19:42
  • 1
    How do you run this? Is it a one-time command, or does it need to be running in a loop or anything like that? Perhaps as part of incron (I hope not). – SDsolar Nov 20 '17 at 0:25
  • @SDsolar It varies. For me, I usually run inotify either with nohup or start it with a custom systemd service. Most often the latter. – maulinglawns Sep 12 '18 at 14:25
9

Use a double negative:

inotifywait -m --exclude "[^j][^s]$" /path -e create -e moved_to |
    while read path action file; do
        echo "The file '$file' appeared in directory '$path' via '$action'"
    done

This will only include javascript files

  • 1
    Nice, I like that it shifts the filtering to inotifywait rather than have it generate huge output for all files and filter afterwards (like in the other answer). Haven't tried, but I guess that would perform a bit faster. – TMG Mar 14 '18 at 9:18
  • This is just what I was looking for. How to modify the --exclude input to watch for .ext files. This is run only once or in a for loop? – kurokirasama Jul 9 '18 at 4:26
  • It's a daemon, so it will run until it crashes or you shut it down :) – Jonas Earendel Jul 10 '18 at 9:30
  • Sorry, missed the first question. inotifywait -m --exclude "[^.][^e][^x][^t]$" /home/jonas/Skrivbord/test -e create -e moved_to | while read path action file; do echo "The file '$file' appeared in directory '$path' via '$action'" done I'm sure the regex can be optimized, but this baby works :) – Jonas Earendel Jul 10 '18 at 20:29
  • Thanxs!! I'll try it out!! – kurokirasama Jul 12 '18 at 2:15
2

Whilst the double-negative approach of the previous answer is a nice idea since (as TMG noted) it does indeed shift the job of filtering to inotifywait, it is not correct.

For example, if a file ends in as then it will not match [^j][^s]$ because the final letter s does not match [^s], therefore it will not be excluded.

In Boolean terms, if S is the statement:

"the final letter is s"

and J is the statement:

"the penultimate letter is j"

then the value of the --exclude parameter should semantically equate to not(J and S), which by De Morgan's laws is not(J) or not(S).

Another potential problem is that in zsh, $path is a built-in variable representing the array equivalent of $PATH, so the while read path ... line will completely mess up $PATH and cause everything to become unexecutable from the shell.

Therefore the correct approach is:

inotifywait -m --exclude "[^j].$|[^s]$" /path -e create -e moved_to |
    while read dir action file; do
        echo "The file '$file' appeared in directory '$dir' via '$action'"
    done

Note the . which is needed after [^j] to ensure that the match is applied in the penultimate position, and also that the | character (representing the boolean OR mentioned above) should not be escaped here because --exclude takes POSIX extended regular expressions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.