Bash script, watch folder, execute command

I am trying to create a bash script with 2 parameters:

  • a directory
  • a command.

I want to watch the directory parameter for changes: when something has been changed the script should execute the command.

I'm running MacOS, not Linux; any pointers or external resources would greatly help as I have see that this is difficult to achieve. Really OI am trying to mimic SASS's watch functionality.

#!/bin/bash

#./watch.sh $PATH $COMMAND

DIR=$1  

ls -l $DIR > $DIR/.begin
#this does not work
DIFFERENCE=$(diff .begin .end)

if [ $DIFFERENCE = '\n']; then
    #files are same
else
    $2
fi 

ls -l $DIR > $DIR/.end

Solution 1:

To continuously recursively monitor folder (md5) and execute a command on change:

daemon() {
    chsum1=""

    while [[ true ]]
    do
        chsum2=`find src/ -type f -exec md5 {} \;`
        if [[ $chsum1 != $chsum2 ]] ; then           
            if [ -n "$chsum1" ]; then
                compile
            fi
            chsum1=$chsum2
        fi
        sleep 2
    done
}

Works on my OS X as I do not have digest.

On Linux, you can use md5sum as a replacement for the md5 command.

Solution 2:

I can’t believe nobody posted this yet.

First make sure inotify-tools are installed.

Then use them like this:

logOfChanges="/tmp/changes.log.csv" # Set your file name here.

# Lock and load
inotifywait -mrcq $DIR > "$logOfChanges" &
IN_PID=$$

# Do your stuff here
...

# Kill and analyze
kill $IN_PID
cat "$logOfChanges" | while read entry; do
   # Split your CSV, but beware that file names may contain spaces too.
   # Just look up how to parse CSV with bash. :)
   path=... 
   event=...
   ...  # Other stuff like time stamps?
   # Depending on the event…
   case "$event" in
     SOME_EVENT) myHandlingCode path ;;
     ...
     *) myDefaultHandlingCode path ;;
done

Alternatively, using --format instead of -c on inotifywait would be an idea.

Just man inotifywait and man inotifywatch for more infos.

Solution 3:

Here's an example of watching a folder for changes and running a the less compiler when one is updated. As a prereq you need npm and these the module onchange. The node community has a whole bunch of different watch commands (like onchange) I'm not aware of any that are compiled self-contained binaries.

npm install less onchange -g

Then you can use something like:

onchange "./stylesheets/*.less" -- lessc main.less > main.css

I prefer a BASH command over the Grunt answer I gave a while back.