Reputation: 16759
I want to execute a command after my app opens the system terminal app. I open the terminal app with the following:
let url = NSURL(fileURLWithPath: "/System/Applications/Utilities/Terminal.app", isDirectory: true) as URL
let configuration = NSWorkspace.OpenConfiguration()
NSWorkspace.shared.openApplication(at: url, configuration: configuration, completionHandler: { app, error in
//app.executeMyCommand("echo hello")
})
And after it opened I want to execute the command "echo hello", as shown in the completionHandler. How can achieve this?
Upvotes: 4
Views: 639
Reputation: 15598
Another solution:
Use NSAppleScript
to execute an AppleScript:
let terminalScript = "echo hello"
/* oneliner * /
let AppleScriptSrc = "tell app \"Terminal\" to do script \"\(terminalScript)\""
/ **/
/* or a script */
let AppleScriptSrc = """
tell app "Terminal"
activate
if number of windows > 0
do script "\(terminalScript)" in tab 1 of window 1
else
do script "\(terminalScript)"
end if
end tell
"""
/**/
if let AppleScript = NSAppleScript(source: AppleScriptSrc) {
var error: NSDictionary?
AppleScript.executeAndReturnError(&error)
if error != nil {
print("Error: \(String(describing: error))")
}
}
To allow sending Apple events:
Upvotes: 1
Reputation: 15598
Another solution:
Send a do script
Apple event to Terminal:
let terminalScript = "echo hello"
if let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: "com.apple.Terminal") {
let configuration = NSWorkspace.OpenConfiguration()
let doScriptEvent = NSAppleEventDescriptor(eventClass: kAECoreSuite,
eventID: kAEDoScript, targetDescriptor: nil, returnID: AEReturnID(kAutoGenerateReturnID),
transactionID: AETransactionID(kAnyTransactionID))
doScriptEvent.setParam(NSAppleEventDescriptor(string: terminalScript), forKeyword:keyDirectObject)
configuration.appleEvent = doScriptEvent
NSWorkspace.shared.openApplication(at: url, configuration: configuration, completionHandler: { app, error in
if error != nil {
print("Error: \(String(describing: error))")
}
})
}
To allow sending Apple events:
Upvotes: 5
Reputation: 27116
One possibility would be to use 'AppleScriptObjc' to control the terminal via an AppleScript from Swift.
Here a complete self-contained example:
ViewController.swift
import Cocoa
import AppleScriptObjC
class ViewController: NSViewController {
var terminalBridge: TerminalBridging?
override func viewDidLoad() {
super.viewDidLoad()
Bundle.main.loadAppleScriptObjectiveCScripts()
let terminalBridgeClass: AnyClass = NSClassFromString("TerminalBridge")!
self.terminalBridge = terminalBridgeClass.alloc() as? TerminalBridging
}
@IBAction func onExecute(_ sender: Any) {
self.terminalBridge?.executeCommand("echo hello")
}
}
TerminalBriding.swift
import Cocoa
@objc(NSObject) protocol TerminalBridging {
func executeCommand(_ cmd: String)
}
TerminalBridge.applescript
Note the suffix .applescript is important. Customize it to your preferences.
script TerminalBridge
property parent : class "NSObject"
to executeCommand:cmd
tell application "Terminal"
do script (cmd as text)
end tell
end executeCommand:
end script
Setup Project in Xcode
Demo
On first run you would see:
If you press 'OK' an entry is added automatically to 'System Preferences/Security & Privacy/Privacy' on first run. Afterward the command is executed.
Upvotes: 3