[macos] Is there a command like "watch" or "inotifywait" on the Mac?

I want to watch a folder on my Mac (Snow Leopard) and then execute a script (giving it the filename of what was just moved into a folder (as a parameter... x.sh "filename")).

I have a script all written up in bash (x.sh) that will move some files and other stuff on input $1 I just need OSX to give me the file name when new files/folders are moved/created into a dir.

Any such command?

This question is related to macos watch inotify

The answer is


My fork of fswatch provides the functionality of inotifywait -m with slightly less (no wait, more! I have a lot more troubles on Linux with inotifywait...) parse-friendly output.

It is an improvement upon the original fswatch because it sends out the actual path of the changed file over STDOUT rather than requiring you to provide a program that it forks.

It's been rock solid as the foundation of a series of scary bash scripts I use to automate stuff.

(this is off-topic) inotifywait on Linux, on the other hand, requires a lot of kludges on top of it and I still haven't figured out a good way to manage it, though I think something based on node.js might be the ticket.


Facebook's watchman, available via Homebrew, also looks nice. It supports also filtering:

These two lines establish a watch on a source directory and then set up a trigger named "buildme" that will run a tool named "minify-css" whenever a CSS file is changed. The tool will be passed a list of the changed filenames.

$ watchman watch ~/src

$ watchman -- trigger ~/src buildme '*.css' -- minify-css

Notice that the path must be absolute.


I ended up doing this for macOS. I'm sure this is terrible in many ways:

#!/bin/sh
# watchAndRun
if [ $# -ne 2 ]; then
    echo "Use like this:"
    echo "   $0 filename-to-watch command-to-run"
    exit 1
fi
if which fswatch >/dev/null; then
    echo "Watching $1 and will run $2"
    while true; do fswatch --one-event $1 >/dev/null && $2; done
else
    echo "You might need to run: brew install fswatch"
fi

Here's a simple single line alternative for users who don't have the watch command who want to execute a command every 3 seconds:

while :; do your-command; sleep 3; done

It's an infinite loop that is basically the same as doing the following:

watch -n3 your-command


This is just to mention entr as an alternative on OSX to run arbitrary commands when files change. I find it simple and useful.


Here's a one-liner using sschober's tool.

$ while true; do kqwait ./file-to-watch.js; script-to-execute.sh; done

If you want to use NodeJS, you can use a package called chokidar (or chokidar-cli actually) for the watching and then use rsync (included with Mac):

Rsync command:

$ rsync -avz --exclude 'some-file' --exclude 'some-dir' './' '/my/destination'

Chokidar cli (installed globally via npm):

chokidar \"**/*\" -c \"your-rsync-command-above\"


watchdog is a cross-platform python API for watching files / directories, and it has builtin "tricks" tool that allows you to trigger actions (including shell commands) when events occur (including new added file, removed file and changed file).


Edit: fsw has been merged into fswatch. In this answer, any reference to fsw should now read fswatch.

I wrote an fswatch replacement in C++ called fsw which features several improvements:

  • It's a GNU Build System project which builds on any supported platform (OS X v. >= 10.6) with

    ./configure && make && sudo make install
    
  • Multiple paths can be passed as different arguments:

    fsw file-0 ... file-n 
    
  • It dumps a detailed record with all the event information such as:

    Sat Feb 15 00:53:45 2014 - /path/to/file:inodeMetaMod modified isFile 
    
  • Its output is easy to parse so that fsw output can be piped to another process.

  • Latency can be customised with -l, --latency.
  • Numeric event flags can be written instead of textual ones with -n, --numeric.
  • The time format can be customised using strftime format strings with -t, --time-format.
  • The time can be the local time of the machine (by default) or UTC time with -u, --utc-time.

Getting fsw:

fsw is hosted on GitHub and can be obtained cloning its repository:

    git clone https://github.com/emcrisostomo/fsw

Installing fsw:

fsw can be installed using the following commands:

    ./configure && make && sudo make install

Further information:

I also wrote an introductory blog post where you can find a couple of examples about how fsw works.


Apple OSX Folder Actions allow you to automate tasks based on actions taken on a folder.


You can use launchd for that purpose. Launchd can be configured to automatically launch a program when a file path is modified.

For example the following launchd config plist will launch the program /usr/bin/logger when the desktop folder of my user account is modified:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>logger</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/logger</string>
        <string>path modified</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>/Users/sakra/Desktop/</string>
    </array>
</dict>
</plist>

To activate the config plist save it to the LaunchAgents folder in your Library folder as "logger.plist".

From the shell you can then use the command launchctl to activate the logger.plist by running:

$ launchctl load ~/Library/LaunchAgents/logger.plist

The desktop folder is now being monitored. Every time it is changed you should see an output in the system.log (use Console.app). To deactivate the logger.plist, run:

$ launchctl unload ~/Library/LaunchAgents/logger.plist

The configuration file above uses the WatchPaths option. Alternatively you can also use the QueueDirectories option. See the launchd man page for more information.


You might want to take a look at (and maybe expand) my little tool kqwait. Currently it just sits around and waits for a write event on a single file, but the kqueue architecture allows for hierarchical event stacking...


I have a GIST for this and the usage is pretty simple

watchfiles <cmd> <paths...>

To illustrate, the following command will echo Hello World every time that file1 OR file2 change; and the default interval check is 1 second

watchfiles 'echo Hello World' /path/to/file1 /path/to/file2 

If I want to check every 5 seconds I can use the -t flag

watchfiles -t 'echo Hello World' /path/to/file1 /path/to/file2 
  • -v enables the verbose mode which shows debug information
  • -q makes watchfiles execute quietly (# will be shown so the user can see the program is executing)
  • -qq makes watchfiles execute completely quietly
  • -h shows the help and usage

https://gist.github.com/thiagoh/5d8f53bfb64985b94e5bc8b3844dba55


Examples related to macos

Problems with installation of Google App Engine SDK for php in OS X dyld: Library not loaded: /usr/local/opt/openssl/lib/libssl.1.0.0.dylib dyld: Library not loaded: /usr/local/opt/icu4c/lib/libicui18n.62.dylib error running php after installing node with brew on Mac Could not install packages due to an EnvironmentError: [Errno 13] How do I install Java on Mac OSX allowing version switching? Git is not working after macOS Update (xcrun: error: invalid active developer path (/Library/Developer/CommandLineTools) Can't compile C program on a Mac after upgrade to Mojave You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory. (mac user) How can I install a previous version of Python 3 in macOS using homebrew? Could not install packages due to a "Environment error :[error 13]: permission denied : 'usr/local/bin/f2py'"

Examples related to watch

What is the Angular equivalent to an AngularJS $watch? AngularJS $watch window resize inside directive Converting Milliseconds to Minutes and Seconds? AngularJS : Clear $watch How to deep watch an array in angularjs? AngularJS : How to watch service variables? OS X Bash, 'watch' command Is there a command like "watch" or "inotifywait" on the Mac? Watching variables in SSIS during debug How do I watch a file for changes?

Examples related to inotify

Is there a command like "watch" or "inotifywait" on the Mac? How to retrieve a module's path?