How can I have a script automatically ran when I start or stop an app without using 3rd party tools?

I'm not developing the application myself, it's a general question that applies to any installed apps.

Clarifications: The application is started/quit be any means possible. The script and the application should be ran serially.

  • As far as I know, you can’t. It’s easily done with Keyboard Maestro but I don’t know of any way to do it without 3rd party software. – TJ Luoma Jan 25 '14 at 0:24
  • Two questions of clarification since you didn't really say WHY you might want to do this: 1) Are you interested in having the script run ONLY when YOU launch/quit an app via the Finder, Dock, launcher, etc or would you want it to be run ANYTIME an application is launched or quit by any means and any user? 2) Would you want this script to be run FIRST and then the app, serially, or just run asynchronously (e.g. for logging purposes). – Jay Allen Jan 25 '14 at 1:13
  • Is it one specific app or all apps? – Tony Williams Jan 25 '14 at 4:08

Assuming answers to my clarification questions above are that you want:

  1. the script to run anytime a specific application is run, regardless of how or by what process or user, and
  2. the script to run in an asynchronous, non-blocking way (e.g. for logging purposes)

...there may be a few ways to do it. None I can think of are terribly elegant or turnkey and all require some sort of demonized process running as root which act to monitor the system for launch events.

Monitoring exec calls via fs_usage

One possible way is to create a daemon (LaunchDaemon) which runs continuously, monitoring a running fs_usage command for exec events. You can see the kind of information you get by running the following command:

sudo fs_usage -f exec

Here's the relevant line when I opened Safari:

17:30:14.465075  posix_spawn    /Applications/Safari.app/Contents/MacOS/Safari    0.000352   launchd.51630812

Here's the output when I opened ran open /Applications/Maps.app from the command line:

17:35:51.594849  execve       /usr/bin/open                                 0.003680 W bash.51635318
17:35:51.642212  posix_spawn  /Applications/Maps.app/Contents/MacOS/Maps    0.003158 W launchd.51635324

Note that nearly all "Applications" (/Applications/*.app) are launched via posix_spawn by launchd and the file used to launch them is /Applications/FOO.app/Contents/MacOS/FOO (where FOO is the application's name). So, theoretically, you could have your LaunchDaemon monitoring this command and triggering your script whenever it outputs the path to the app you're monitoring:

sudo fs_usage -w -f exec | perl -lne 'm/.*posix_spawn +(.*?) +[0-9.]+ . launchd.\d+/sm && print $1'

Monitoring launchservicesd via lsappinfo

I wasn't terribly happy with the above because it's kinda hacky, watching for filesystem events instead of the launching event that triggered them. And then I realized, "launchd"! Enter Launch Services:

Leading to:

lsappinfo listen +all forever

And Voilà, you not only have launching, but also get notified when an app quits. The keys you care about are the following:

  • kLSNotifyApplicationLaunch
  • kLSNotifyApplicationBirth
  • kLSNotifyLaunchFinished
  • kLSNotifyApplicationDeath

You must log in to answer this question.

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