Question: I want to replace my CI bash scripts with swift. I can't figure out how to invoke normal terminal command such as `ls` or `xcodebuild`

```
#!/usr/bin/env xcrun swift

import Foundation // Works
println("Test") // Works
ls // Fails
xcodebuild -workspace myApp.xcworkspace // Fails

```

---

```
$ ./script.swift
./script.swift:5:1: error: use of unresolved identifier 'ls'
ls // Fails
^
... etc ....

```

Answer: 
Just to update this since Apple has deprecated both .launchPath and launch(), here's an updated utility function for Swift 4 that should be a little more future proof.

Note: Apple's documentation on the replacements ([run()](https://developer.apple.com/documentation/foundation/process/2890105-run), [executableURL](https://developer.apple.com/documentation/foundation/process/2890106-executableurl), etc) are basically empty at this point.

```
import Foundation

// wrapper function for shell commands
// must provide full path to executable
func shell(_ launchPath: String, _ arguments: [String] = []) -> (String?, Int32) {
  let task = Process()
  task.executableURL = URL(fileURLWithPath: launchPath)
  task.arguments = arguments

  let pipe = Pipe()
  task.standardOutput = pipe
  task.standardError = pipe

  do {
    try task.run()
  } catch {
    // handle errors
    print("Error: \(error.localizedDescription)")
  }

  let data = pipe.fileHandleForReading.readDataToEndOfFile()
  let output = String(data: data, encoding: .utf8)

  task.waitUntilExit()
  return (output, task.terminationStatus)
}

// valid directory listing test
let (goodOutput, goodStatus) = shell("/bin/ls", ["-la"])
if let out = goodOutput { print("\(out)") }
print("Returned \(goodStatus)\n")

// invalid test
let (badOutput, badStatus) = shell("ls")

```

Should be able to paste this directly into a playground to see it in action.
I'm in the process of re-factoring some existing Objective-C code that used NSTask to Swift, and one key thing missing in other answers is how you should be handling large quantities of stdout/stderr output. Failure to do this seems to result in hangs in the launched process.

One of the commands I commonly launch can produce hundreds of KB of output to both stdout and stderr.

To deal with this, I buffer the output thusly:

```
import Foundation

struct ShellScriptExecutor {

    static func runScript(_ script: ShellScript) -> ShellScriptResult {
        var errors: String = ""
        let tempFile = copyToTempFile(script)
        let process = Process()
        let stdout = Pipe()
        let stderr = Pipe()
        var stdoutData = Data.init(capacity: 8192)
        var stderrData = Data.init(capacity: 8192)

        process.standardOutput = stdout
        process.standardError = stderr
        process.executableURL = URL(fileURLWithPath: "/bin/zsh")
        process.arguments = [tempFile]

        do {
            try process.run()

            // Buffer the data while running
            while process.isRunning {
                stdoutData.append(pipeToData(stdout))
                stderrData.append(pipeToData(stderr))
            }

            process.waitUntilExit()

            stdoutData.append(pipeToData(stdout))
            errors = dataToString(stderrData) + pipeToString(stderr)
        }

        catch {
            print("Process failed for " + tempFile + ": " + error.localizedDescription)
        }

        // Clean up
        if !tempFile.isEmpty {
            do {
                try FileManager.default.removeItem(atPath: tempFile)
            }

            catch {
                print("Unable to remove " + tempFile + ": " + error.localizedDescription)
            }
        }

        return ShellScriptResult(stdoutData, script.resultType, errors)
    }

    static private func copyToTempFile(_ script: ShellScript) -> String {
        let tempFile: String = URL(fileURLWithPath: NSTemporaryDirectory())
            .appendingPathComponent(ProcessInfo.processInfo.globallyUniqueString + ".sh", isDirectory: false).path

        if FileManager.default.createFile(atPath: tempFile, contents: Data(script.script.utf8), attributes: nil) {
            return tempFile;
        }
        else {
            return ""
        }
    }

    static private func pipeToString(_ pipe: Pipe) -> String {
        return dataToString(pipeToData(pipe))
    }

    static private func dataToString(_ data: Data) -> String {
        return String(decoding: data, as: UTF8.self)
    }

    static private func pipeToData(_ pipe: Pipe) -> Data {
        return pipe.fileHandleForReading.readDataToEndOfFile()
    }
}

```

(ShellScript and ShellScriptResult are just simple wrapper classes)