Swift Process and osascript: so much easier than the command line

I use osascript a lot to automate things that need automating and until yesterday, I did so almost exclusively from shell scripts. Then,  while developing some sample code the other day, I discovered how much easier it is to call osascript from a command-line utility, even for the most trivial of scripts.

let script = """
  set appName to "\(appName)"
  tell application "System Events"
	if visible of application process appName is true then
		set visible of application process appName to false
	else
		set visible of application process appName to true
	end if
  end tell
  """

With Swift’s triple-quoted multiline string, you need little if any escaping and your script can basically be copy/pasted from the Script Editor app. Plus string interpolation enables you programmatically customize your AppleScript code.

For your Process, set your launchPath to "/usr/bin/osascript" and your arguments to ["-e", script]. Then launch and wait until exit.

if #available(macOS 10.13, *) {
    guard (try? process.run()) != nil
        else { throw RuntimeError.operationError }
} else {
    process.launch()
}
process.waitUntilExit()

Why is it worth creating an entire Xcode project to deal with a little osascript work? For me, it’s a big win when it is part of a larger utility. With the Swift Argument Parser, I’ve been porting a lot of my scripts — both shell scripts and swift scripts — to compiled utilities and I find that I tend to lean on osascript a lot more than I thought I did to automate my system.

2 Comments

  • Code generation via string munging is potentially dangerous (see: every code injection attack ever). The cleanest and safest way to pass string values to osascript+AppleScript is via argv:


    on run {arg1, arg2, …}
    ...
    end

    osascript -e "$script" - "$arg1" "$arg2" …

    p.arguments = ["-e", script, "-", arg1, arg2, …]

    For anything more complex, best to call your AppleScript handlers directly via the AppleScript-ObjC bridge:

    appscript.sourceforge.net/asoc.html

  • Last week I used this trick for an inline a Metal shader library. It’s for a CLI w/ no bundle, so i was really happy to have the option to inline.

    My only complaint is Xcode syntax coloring.