How do I run a terminal command in a Swift script? (e.g. xcodebuild) How do I run a terminal command in a Swift script? (e.g. xcodebuild) swift swift

How do I run a terminal command in a Swift script? (e.g. xcodebuild)


If you don't use command outputs in Swift code, following would be sufficient:

#!/usr/bin/env swiftimport Foundation@discardableResultfunc shell(_ args: String...) -> Int32 {    let task = Process()    task.launchPath = "/usr/bin/env"    task.arguments = args    task.launch()    task.waitUntilExit()    return task.terminationStatus}shell("ls")shell("xcodebuild", "-workspace", "myApp.xcworkspace")

Updated: for Swift3/Xcode8


If you would like to use command line arguments "exactly" as you would in command line (without separating all the arguments), try the following.

(This answer improves off of LegoLess's answer and can be used in Swift 5)

import Foundationfunc shell(_ command: String) -> String {    let task = Process()    let pipe = Pipe()        task.standardOutput = pipe    task.standardError = pipe    task.arguments = ["-c", command]    task.launchPath = "/bin/zsh"    task.launch()        let data = pipe.fileHandleForReading.readDataToEndOfFile()    let output = String(data: data, encoding: .utf8)!        return output}// Example usage:shell("ls -la")


The problem here is that you cannot mix and match Bash and Swift. You already know how to run Swift script from command line, now you need to add the methods to execute Shell commands in Swift. In summary from PracticalSwift blog:

func shell(_ launchPath: String, _ arguments: [String]) -> String?{    let task = Process()    task.launchPath = launchPath    task.arguments = arguments    let pipe = Pipe()    task.standardOutput = pipe    task.launch()    let data = pipe.fileHandleForReading.readDataToEndOfFile()    let output = String(data: data, encoding: String.Encoding.utf8)    return output}

The following Swift code will execute xcodebuild with arguments and then output the result.

shell("xcodebuild", ["-workspace", "myApp.xcworkspace"]);

As for searching the directory contents (which is what ls does in Bash), I suggest using NSFileManager and scanning the directory directly in Swift, instead of Bash output, which can be a pain to parse.