10

Is there a simple way to automatically run a (Terminal) command every time a file is changed in a specific folder?

This should be possible via the command line, or a system built-in application, no third-party applications.

Any ideas?

6

Save a property list like this as ~/Library/LaunchAgents/test.plist:

<?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>test</string>
    <key>ProgramArguments</key>
    <array>
        <string>say</string>
        <string>yy</string>
    </array>
    <key>WatchPaths</key>
    <array>
        <string>~/Desktop/</string>
    </array>
</dict>
</plist>

The agent can be loaded with launchctl load ~/Library/LaunchAgents/test.plist or by logging out and back in. Applying changes requires unloading and loading the plist.

Tilde expansion (~/) works in WatchPaths by default. EnableGlobbing adds wildcard and tilde expansion for ProgramArguments, but it doesn't affect Program or WatchPaths.

If a watched file is modified within ten seconds from the last invocation, a message like this is added to system.log:

com.apple.launchd.peruser.501[146]: (test) Throttling respawn: Will start in 7 seconds

One way to get rid of the messages is to add something like sleep 10 to the end of scripts. Setting ThrottleInterval to 10 doesn't help.

Changes in subfolders of watched folders aren't detected.

See man launchd and man launchd.plist for more information.

5

entr(1) is a utility for running commands when files change. It reads a list of file on STDIN and uses kqueue(2) to avoid polling.

Example:

ls my_project/*.html | entr echo "file changed"
3

You could use Folder Actions, which lets you execute (Automator) scripts whenever contents in a folder change. As far as I know, Automator has a template that lets you easily create a new folder action and attach it to the desired folder. And by adding a "Run Shell Script" action, you should just get the desired effect.

  • 5
    Thanks, but it appears that "Folder Actions" are only triggered when a file is added to the folder, not when an existing file is checked. – Louis B. Feb 17 '12 at 15:06
3

Folder actions are fine for triggering when a file is added or modified.

However, if your definition of changed includes deleting a file, OSX Folder actions does not detect if a file has been removed.

To answer the question:

  1. Download the FileWatcher dependencies from here: https://github.com/eonist/swift-utils

  2. Familiarize your self with running swift in the comandline: http://krakendev.io/blog/scripting-in-swift

  3. Use this code to watch a folder.

Code:

var fileWatcher = FileWatcher(["~/Desktop/test/".tildePath])/*<---the fileWatcher instance must be scoped to your class*/

fileWatcher!.event = { event in
    Swift.print(self?.someVariable)//Outputs: a variable in your current class
    Swift.print(event.description)//Outputs: a description of the file change
}
1

Automator has a type of workflow called a "Folder Action" which automatically runs when something is added to a folder. Create one, then use the action "Run Shell Script."

  • 4
    Thanks, but it appears that "Folder Actions" are only triggered when a file is added to the folder, not when an existing file is checked. – Louis B. Feb 17 '12 at 15:06
  • Oh, okay. Sorry. – Timothy Mueller-Harder Feb 17 '12 at 21:05
0

You might want to try something like this:

touch /tmp/dirb.tmp
while true do 
  ls /thedirtocheck > /tmp/dira.tmp 
  diff /tmp/dira.tmp /tmp/dirb.tmp || echo "something changed" 
  cp /tmp/dira.tmp /tmp/dirb.tmp 
  sleep 100 
done
  • You need at least ls -l to catch file changes as well. – nohillside Feb 17 '12 at 12:15
  • right.... missed that – Holger von Ameln Feb 17 '12 at 17:57

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .