How to use LaunchAgents to monitor folder contents in OS X

NewTerminalIconXWatching folders for various changes in OS X can be exceptionally useful for automating tasks to handle any files added to the folder. This can be especially useful as a security measure for determining unwanted changes to key system folders. One robust solution for this is to use Apple’s Folder Actions feature for monitoring folders, and while still one I prefer and recommend, another approach is to use the system launcher.

The launcher is a background process called “launchd” that is the main umbrella process for all user processes in OS X, and is launched only second to the OS X Kernel at bootup. All other processes run underneath it, including a second instance of it that runs as an umbrella process for your user account. In this way, the environment and conditions for your user account can be separate from that of other user accounts, giving more control for resource management.

Since it is a process that manages others, launchd has a number of options for scheduling tasks and running them conditionally, which developers often use for their purposes, and which you can tap into for your own custom needs.

As with Folder Actions, if you use the system launcher you will need to create some scripts for OS X, and doing so will require the use of a text editor and the Terminal, so while familiarity with these environments is not required, at least a basic understanding will be beneficial to have.

The basic setup of a launcher script is a text document in Apple’s “key and value” Property List XML file format, that has two requirementsL a Label key, and a Program or Program Argument key. Such a script will look like the following:

<?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>MyAgent</string>
     <key>ProgramArguments</key>
     <array>
          <string>/path/to/script/or/program</string>
     </array>
</dict>
</plist>

In this case, the label of the property list is “MyAgent,” and the program that is launched is pointed to along the path of its string value. With these two label and program properties, the script can open the program and register it with the system under the given label. You can then start and stop it with the Terminal’s “launchctl” utility by running the following commands in the Terminal:

launchctl start LABEL
launchctl stop LABEL

To automate this starting and stopping, you need to provide additional conditions to the script for when the specified program will be run. The options include setting time intervals, calendar dates and times, whether or not a drive is attached, among other specific conditions that the program is to run. As with setting the label and specifying the program, you do this using keys and corresponding values for the various options.

For the purposes of this property list, we are going to set a WatchPaths condition, that will set up the script to monitor the specified filesystem paths and then invoke the program whenever the watched folders are changed.

1. Create a script such as the following to issue an alert whenever run, and save it with the name “notice.sh” in your Documents folder (this one is just a simple AppleScript-based notification, but you can use any custom script you would like):

#/bin/bash
osascript -e "tell Application \"System Events\" to display alert\
 \"Watched Folder contents changed\""

2. Run the following Terminal command to make the script executable:

chmod +x ~/Documents/notice.sh

3. Create a plain text file and copy the following template plist structure into it, then modify the Label string to something like “WatchFolders,” then the Program string to the full path of the script in your Documents folder (ie, something like /Users/username/Documents/notice.sh). Then change the strings for the WatchPaths values to the full paths of any folder you would like to monitor for additions.

<?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>MyAgent</string>
     <key>ProgramArguments</key>
     <array>
          <string>/path/to/script/or/program</string>
     </array>
     <key>WatchPaths</key>
     <array>
           <string>/path/to/first/watched/folder/</string>
           <string>/path/to/second/watched/folder/</string>
           <string>/path/to/third/watched/folder/</string>
     </array>
</dict>
</plist>

When done, save the plist with a name like “watchpaths.plist” and place it into your username/Library/LaunchAgents/ folder (to get here, hold the Option key down and choose Library from the Go menu in the Finder. When done, you can run the following command to load the launch agent script:

launchctl load ~/Library/LaunchAgents/watchpaths.plist

This will have the launchd process for your user account keep track of the various folders you have it configured to watch, and when you add or remove an item, then the “notice” script you created will run and display the alert.

This approach does have some limitations over the default use of the AppleScripts provided with Folder Actions. For example, the Folder Actions scripts will by default give you an option to reveal the new items added to the folders, and the system launcher script will not pass to the script which of its watched folders were modified; however, with some fancy shell scripting or by using advanced AppleScripts, you can program a way to have the system determine the changed files and present them to you.

This type of programming can be situation specific, so I will not cover them here; however, they can all be managed using the system launcher in the way I mentioned above.

To undo this launchd addition, go to the username > Library > LaunchAgents folder and remove the plist file you created there, followed by logging out and back into your account.

6 thoughts on “How to use LaunchAgents to monitor folder contents in OS X

  1. Robert Hancock

    I get the Message Invalid Property list for the following code when U try to launch the agent.

    [code]

        Label
        WatchFolders
        ProgramArguments

        /Clone/Users/roberthancock/Documents/notice.sh

        WatchPaths
       
              /Clone/Users/roberthancock/Desktop/Files/
       

    [/code]

    Any ideas what I have done wrong

  2. Robert Hancock

    Seems like this site does not support [code] [/code]!

        Label
        WatchFolders
        ProgramArguments

        /Clone/Users/roberthancock/Documents/notice.sh

        WatchPaths
       
              /Clone/Users/roberthancock/Desktop/Files/
       

  3. Robert Hancock

    Topher, I followed your instructions to the letter but I am getting two error messages on Yosemite!
    First, I get a Syntax error saying

    Expected end of line, etc. but found “””.

    on the notice.sh script when I try to save it in Apple Script editor. I cannot see what is wrong with it. The first ” is highlighted when the Syntax error message appears.

    Second, I get an Invalid Property list message when I try to run the agent.
    I have double checked that I am following you exactly, so perhaps you would like to revisit the code and see if something changed in Yosemite.

    1. Dave

      Not sure if this is your issue, but I have found that sometimes opening a file in the in-built OS text editor replaces standard quotes with italic looking ones. This then gave me a similar issue to what you’re getting. I had to go and replace the italic looking quotes with standard ones and it all started working again.

Comments are closed.