3

I have a bash script that processes some data using inotify-tools to know when certain events took place on the filesystem. It works fine if run in the bash console, but when I try to run it as a daemon it fails. I think the reason is the fact that all the output from the inotifywait command call goes to a file, thus, the part after | while doesn't get called anymore. How can I fix that? Here is my script.

#!/bin/bash

inotifywait -d -r \
-o /dev/null \
-e close_write \
--exclude "^[\.+]|cgi-bin|recycle_bin" \
--format "%w:%&e:%f" \
$1|
while IFS=':' read directory event file
do

    #doing my thing

done

So, -d tells inotifywait to run as daemon, -r to do it recursively and -o is the file in which to save the output. In my case the file is /dev/null because I don't really need the output except for processing the part after the command (| while...)

Rad'Val
  • 8,895
  • 9
  • 62
  • 92

2 Answers2

9

You don't want to run inotify-wait as a daemon in this case, because you want to continue process output from the command. You want to replace the -d command line option with -m, which tells inotifywait to keep monitoring the files and continue printing to stdout:

   -m, --monitor
          Instead  of exiting after receiving a single event, execute
          indefinitely.  The default behaviour is to exit  after  the
          first event occurs.

If you want things running in the background, you'll need to background the entire script.

larsks
  • 277,717
  • 41
  • 399
  • 399
  • Wait a sec, I know that, but I need it to run in background so that I can close the console, logout etc and it should still monitor my directories. – Rad'Val May 10 '12 at 12:05
  • That's what I meant by "backgrounding the entire script". You need to make your *script* run as a daemon, not just the `inotifywait` program. – larsks May 10 '12 at 12:53
  • But man page says this "-d, --daemon Same as --monitor, except run in the background logging events to a file that must be specified by --outfile. Implies --syslog. " – Chris F Dec 15 '17 at 14:36
  • @ChrisF, that will background `inotifywait` itself, but that doesn't make any sense if you are piping the output of that into a script. – larsks Dec 15 '17 at 16:09
  • 1
    This won't work. His loop depends on inotifywait being interrupted when the event occurs. This will never happen with -m. He should just place the inotifywait command in some sort of loop with whatever command he wants to execute. This will allow it to persist without -m or -d. – thebunnyrules Jan 24 '18 at 02:26
  • It works fine with -m, I do this all the time. Do not pass '-d'. A single inotifywait invocation runs in the foreground, and on each event it detects, it outputs a line to stdout. Those lines are read by the 'read', causing the 'while' loop to iterate once. Remember, when you have a pipeline, your shell runs each command in parallel, feeding the output of one to the input of the next. There is no need to interrupt the execution of inotifywait. (and yes, as stated the OP needs to run this whole script in the background / as a daemon or service, not just the inotifywait process) – Jonathan Hartley Jan 19 '23 at 05:19
2

Here's a solution using nohup: (Note in my testing, if I specified the -o the while loop didn't seem to be evaluated)

nohup inotifywait -m -r \
  -e close_write \
  --exclude "^[\.+]|cgi-bin|recycle_bin" \
  --format "%w:%&e:%f" \
  $1 |
while IFS=':' read directory event file
do
  #doing my thing
done >> /some/path/to/log 2>&1 &