6

How can I run a shell script from cocoa application using Swift?

I have a shell script file.sh that I want to run from within my cocoa application. How can I do this using Swift?

Any help appreciated! :)

2 Answers 2

13

Pre Swift 3

You can use NSTask (API reference here) for this.

A NSTask takes (among other things) a launchPath which points to your script. It can also take an array of arguments and when you are ready to launch your task, you call launch() on it.

So...something along the lines of:

var task = NSTask()
task.launchPath = "path to your script"
task.launch()

Post Swift 3

As @teo-sartory points out in his comment below NSTask is now Process, documented here

The naming and way you call it has changed a bit as well, here is an example of how to use Process to call ls

let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/ls")
try? process.run()

If you want better access to/more control over the output from your invocation, you can attach a Pipe (documented here).

Here is a simple example of how to use that:

let process = Process()
process.executableURL = URL(fileURLWithPath: "/bin/ls")

// attach pipe to std out, you can also attach to std err and std in
let outputPipe = Pipe()
process.standardOutput = outputPipe

// away we go!
try? process.run()

//read contents as data and convert to a string
let output = outputPipe.fileHandleForReading.readDataToEndOfFile()
let str = String(decoding: output, as: UTF8.self)
print(str)

Would you like to know more

You can have a look at:

Hope that helps you.

Sign up to request clarification or add additional context in comments.

1 Comment

NSTask is now Process()
7

I found this function on the web:

@discardableResult
private func shell(_ args: String) -> String {
    var outstr = ""
    let task = Process()
    task.launchPath = "/bin/sh"
    task.arguments = ["-c", args]
    let pipe = Pipe()
    task.standardOutput = pipe
    task.launch()
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    if let output = String(data: data, encoding: .utf8) {
        outstr = output as String
    }
    task.waitUntilExit()
    return outstr
}

Here's the call:

shell("/pathToSh/file.sh")

4 Comments

That's wrong. The full command from your func is: /bin/sh -c sh /pathToSh/file.sh And this obviously doesn't work..
@AlessandroOrnano just re-tested with shell("open /Folder/") and it worked just fine. Maybe you should check what -c does... stackoverflow.com/questions/3985193/what-is-bin-sh-c
Even your second example is wrong, open opens file from a shell, don't change directory. Your method launch bash -c that mean it will launch bash and execute the command after -c, so it's like bash -c bash file.sh and it doesn't work.
I never said I wanted to change the directory, I wanted to open it and it did. So on that note, it works. Now, the command sh is meant to run the script... Your version works as well though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.