Controlling/stopping Applescript Applications.

Upfront, I’ve only used this on Pre-Mavericks systems, so please feel free to chime-in with results on Yosemite and friends.

Very often when running either Stay-Open scripts, or long-running scripts with complex operations, it can sometimes become necessary to be able to exert control over them.

Often, this takes the shape of periodic interrupts that bring up dialogs enabling some gear-shifting, or quit via our good old friend:


error number -128

So why no “System Events” / “Killall” commands?

Well because Applescript applications all show up to ps -ax as “applet”. This is fine if you only use that one AS app, but I usually have 7 or more running. Also, if you use an NSUIelement in the Info.plist to hide them from the Dock, they cannot be force-quit in the usual way (this ‘hiding’ is often desirable, as the system’s ‘Focus’ will jump to a stay open app every time it cycles - this sucks if the return number is say every 5 seconds).

Well there is a bit of TomHackery to the rescue.

Within the application bundle you will find the applet executable (/Contents/MacOS/applet). The cool thing is that you can elect to simply call it something else! Like myApp or whatever (this does not need a file-extension. Don’t add one, or it won’t work).

Next, we have to aim the application toward the new item. In the Info.plist (/Contents/Info.plist), you can simply change the applet under CFBundleExecutable to the new name so it would then look like:

CFBundleExecutable
myApp

Then you want to Re-copy the application bundle to a new location (ideally with option+copy) and then it will now use the new executable.

The benefit is you can now use a ps -ax | grep to to detect the app and stop it with a simple:


do shell script "killall myApp"

Also, should it be needed, the new app-name can be used to Re-Nice your custom app if higher executable priority is needed.

P.S. Just realized I forget to mention that you should also rename the .rsrc file to the chosen new name. It can be found at (/Contents/Resources/). If you don’t rename this too, will always bring up the “Run” or “Quit” dialog. Sorry - has been a while since writing one of these!

First of all nice totur, even when you don’t want to manage it in ps to kill it, sometimes you want another name for other reasons. However to complete the list of solutions for this problem as an alternative to killall: with pkill command you can kill applets by it’s path:

do shell script "pkill -f ^/Applications/MyApp.app/"

While the name of executable may be the same, the path to each applet is unique. If applets are launched by scripts you definitely know their path. if the applet is launched and a stay open script you can use the path to command to get it’s path like this:

set thePath to POSIX path of (path to application "MyApp")
do shell script "pkill -f ^" & quoted form of thePath

The -f option will match the regex against all arguments. Therefore the regex starts with a caret so the match is only matched against the first argument which is always the full path to the executable.

Probably works well enough for a local-machine. Learned the hard way a few years ago with an app, you can never assume everybody puts apps in the same place. Besides, path-instructions just really break portability on general terms.

Or alternatively:

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"

set posixPath to "/path/to/the.app/"
set theApps to current application's NSWorkspace's sharedWorkspace()'s runningApplications()
repeat with anApp in theApps
	if anApp's bundleURL()'s |path|() as text = posixPath then
		anApp's forceTerminate()
		exit repeat
	end if
end repeat

Am Digging this! Sadly, I only write Applescript for Vintage/Older Macs (10.4-10.8), and many of these sexy-new toys don’t work for us, but still pretty nice!

In that case you can use the bundle identifier, which should be unique for every app.

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "AppKit"

set bundleId to "com.mycompanyname.super-duper.app"
set theApps to current application's NSRunningApplication's runningApplicationsWithBundleIdentifier:bundleId
repeat with anApp in theApps
	anApp's forceTerminate()
end repeat

Sadly Bundle identifiers don’t actually work that way. They show up on the Dock, Command+Tab and such, but with Applescript apps, it is System Events that is actually doing everything behind the scenes. The MacOS Applet, is the linkage to System Events, and pretty much the only way to stop an Applescript App, without a force-quit (which doesn’t work if the apps have been ‘hidden’ as mentioned in the OP).

The method mentioned above allows automated stopping of Applescript apps, in a really seamless way.

True therefore In my second example I get the path by application name that is running currently. So the path itself is entirely dynamic, in other words it doesn’t matter where you have your applet installed. I’m not saying you should use my example over yours, just adding some information for other readers to the subject “Controlling/stopping AppleScript Applications”.

Not bad - this does work. The only side effect, is if the app isn’t already running, it starts it (not a passive approach), but certainly worth exploring.

You can avoid that by checking the state of the application first before getting it’s path or killing it.

set appName to "MyApp"
if application appName is running then
	set thePath to POSIX path of (path to application appName)
	do shell script "pkill -f ^" & quoted form of thePath
end if