NSTask lets you run command-line calls in your app My initial quest was to find a way to call multiple command line calls in one NSTask, But The proper cocoa way to do this would be to create an NSTask for each command, setting each task’s arguments as necessary. And Apparently using the NSTask in the first place is more of a hack and NSTask is known to be slow.🔑 Rather you should try to find a Cocoa API for what you are trying to accomplish with NSTask. But Sometimes you need to test a theory first. Before diving deep into a complex API.
Running a shell script in terminal:
- Create my_script.sh
- Add some commands: (every new line is a command call)
#!/bin/sh echo "Hello world" echo "Hello world"
- In terminal write: ‘chmod 755 ~/Desktop/my_script.sh’ (this sets a permission to run the script)
- In terminal write: ‘~/Desktop/my_script.sh’
- Terminal should now say hello two times
Resources:
- NSTask & NSNotification: http://cocoadevcentral.com/articles/000025.php
- NSTask in swift3 (Process): https://www.raywenderlich.com/125071/nstask-tutorial-os-x
- AMShellWrapper (objc): http://www.harmless.de/download/AMShellWrapper.zip
Run .sh files with NSTask:
- The “-c” argument tells sh to parse the next argument as a script 🔑
- The “-c” also enables the command-line to find the correct path where the operation is located , so you don’t have to specify the path for where the method echo is. You just write echo and command-line locates the path 🔑
task.launchPath = "/bin/sh" task.arguments = ["-c","~/Desktop/my_script.sh"]
my_script.sh: (remember to set permissions for it to be executed)
#!/bin/sh echo $1#This should print additional arguments, but it doesnt seem to work echo "Hello world" echo "Saying hello again" /usr/local/git/bin/git log -3 --pretty=format:"Sha1: %h"#calling a git method
This approach is able to call multiple commands from NSTask, but unable to pass arguments to the .sh script.
Run a .sh shell script from NSTask with argument support:
By calling the .sh script from the launchPath and using .arguments the .sh + NSTask + argument support combo seem to work.
ASync NSTask research:
if isRunning {//you set the isRunning your self when you run a task
buildTask.terminate()//stops the task if it hangs etc
}
Execute a shell task asynchronously example:
http://iswift.org/cookbook/execute-a-shell-task-asynchronously
To get notified of streaming data:
listen to: NSFileHandleDataAvailableNotification
// Create a Task instance
let task = NSTask()
// Set the task parameters
task.launchPath = "/usr/bin/env"
task.arguments = ["ls", "-la"]
// Create a Pipe and make the task
// put all the output there
let pipe = NSPipe()
task.standardOutput = pipe
let outputHandle = pipe.fileHandleForReading
outputHandle.waitForDataInBackgroundAndNotify()
// When new data is available
var dataAvailable : NSObjectProtocol!
dataAvailable = NSNotificationCenter.defaultCenter().addObserverForName(NSFileHandleDataAvailableNotification,
object: outputHandle, queue: nil) { notification -> Void in
let data = pipe.fileHandleForReading.availableData
if data.length > 0 {
if let str = NSString(data: data, encoding: NSUTF8StringEncoding) {
print("Task sent some data: \(str)")
}
outputHandle.waitForDataInBackgroundAndNotify()
} else {
NSNotificationCenter.defaultCenter().removeObserver(dataAvailable)
}
}
// When task has finished
var dataReady : NSObjectProtocol!
dataReady = NSNotificationCenter.defaultCenter().addObserverForName(NSTaskDidTerminateNotification,
object: pipe.fileHandleForReading, queue: nil) { notification -> Void in
print("Task terminated!")
NSNotificationCenter.defaultCenter().removeObserver(dataReady)
}
// Launch the task
task.launch()
Example is from this link: http://iswift.org/cookbook/execute-a-shell-task-asynchronously
Todos:
- Try to speed test the NSTask + .sh + arguments combo.
- Try to speed test loop Multiple NSTask instance test
- Try to test the Async NSTask. Background processes are nice!
- Try searching for NSTask on github
- Gather more information