Search code examples
linuxshellinitinotify

How to run inotifywait continuously and run it as a cron or deamon?


I've built a shell script that uses inotifywait to automatically detect file changes on a specific directory. When a new PDF file is dropped in the directory this script should go off and it should then trigger ocropus-parser to execute some commands on it. The code:

#!/bin/sh
inotifywait -m ~/Desktop/PdfFolder -e create -e moved_to |
while read path action file; do
    #echo "The file '$file' appeared in directory '$path' via '$action'"
    # Check if the file is a PDF or another file type.
    if [ $(head -c 4 "$file") = "%PDF" ]; then
        echo "PDF found - filename: " + $file
        python ocropus-parser.py $file
    else
        echo "NOT A PDF!"
fi
done

This works pretty well when I run this script through the terminal with ./filenotifier.sh but when I reboot my Linux (Ubuntu 14.04) my shell will no longer run and it will not restart after a reboot. I've decided to create an init script that starts at boot time (I think). I did this by copying the file filenotifier.sh to init.d:

sudo cp ~/Desktop/PdfFolder/filenotifier.sh /etc/init.d/

I've then gave the file the correct rights:

sudo chmod 775 /etc/init.d/filenotifier.sh

and finally I've added the file to update-rc.d:

sudo update-rc.d filenotifier.sh defaults

However when I reboot and drop a PDF in the folder ~/Desktop/PdfFolder nothing will happen and it seems that the script does not go off. I'm really not experienced with init.d, update-rc.d and deamon so I'm not sure what is wrong and if this is even a good approach or not.

Thanks, Yenthe


Solution

    • Being an init-script, you should add the LSB header to your script, like this:

      #!/bin/sh
      ### BEGIN INIT INFO
      # Provides:          filenotifier
      # Required-Start:    $remote_fs $syslog
      # Required-Stop:     $remote_fs $syslog
      # Default-Start:     2 3 4 5
      # Default-Stop:      0 1 6
      # Short-Description: Something
      # Description:       Something else
      ### END INIT INFO
      
      inotifywait -m ...
      

      This way, you can ensure that your script runs when all mount points are available (thanks to Required-Start: $remote_fs). This is essential if your home directory is not on the root partition.

    • Another problem is that in your init-script you're using ~:

      inotifywait -m ~/Desktop/PdfFolder ...
      

      The ~ expands to the current user home directory. Init-scripts are run as root, so it'll expand to /root/Desktop/PdfFolder. Use ~<username> instead:

      inotifywait -m ~yenthe/Desktop/PdfFolder ...
      

      (Assuming that your username is yenthe.)

      Or perhaps switch user before starting (using sudo).

    • $file is the basename without the path to the directory. Use "$path/$file" in your commands:

      "$(head -c 4 "$path/$file")"
      python ocropus-parser.py "$path/$file"
      

      Maybe consider using name instead of file, to avoid confusion.

    • If things are not working, or if in general you want to investigate something, remember to use ps, like this:

      ps -ef | grep inotifywait
      

      ps will tell you, for example, whether your script is running and if inotifywait was launched with the correct arguments.

    • Last but not least: use "$file", not $file; use "$(head -c 4 "$file")", not $(head -c 4 "$file"); use read -r, not read. These tips can save you a lot of headaches in the future!