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.