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: 
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 Foundation

func 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.standardInput = nil
    task.launch()

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

    return output
}

// Example usage:
shell("ls -la")

```

**Updated / safer function calls 10/23/21:**
It's possible to run into a runtime error with the above shell command and if so, try swapping to the updated calls below. You'll need to use a do catch statement around the new shell command but hopefully this saves you some time searching for a way to catch unexpected error(s) too.

**Explanation**: Since task.launch() isn't a throwing function it cannot be caught and I was finding it to occasionally simply crash the app when called. After much internet searching, I found the Process class has deprecated task.launch() in favor of a newer function task.run() which does throw errors properly w/out crashing the app. To find out more about the updated methods, please see: <https://eclecticlight.co/2019/02/02/scripting-in-swift-process-deprecations/>

```
import Foundation

@discardableResult // Add to suppress warnings when you don't want/need a result
func safeShell(_ command: String) throws -> String {
    let task = Process()
    let pipe = Pipe()

    task.standardOutput = pipe
    task.standardError = pipe
    task.arguments = ["-c", command]
    task.executableURL = URL(fileURLWithPath: "/bin/zsh") //<--updated
    task.standardInput = nil

    try task.run() //<--updated

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

    return output
}

```

Examples:

```
// Example usage capturing error:
do {
    try safeShell("ls -la")
}
catch {
    print("\(error)") //handle or silence the error here
}

// Example usage where you don't care about the error and want a nil back instead
let result = try? safeShell("ls -la")

// Example usage where you don't care about the error or the return value
try? safeShell("ls -la")

```

Note: For the last case where you are using `try?` and aren't using the result, for some reason the compiler still warns you even though it's marked as `@discardableResult`. This only happens with `try?`, not `try` within a `do-try-catch` block or from within a throwing function. Either way, you can safely ignore it.
Small improvement with the support for env variables:

```swift
func shell(launchPath: String,
           arguments: [String] = [],
           environment: [String : String]? = nil) -> (String , Int32) {
    let task = Process()
    task.launchPath = launchPath
    task.arguments = arguments
    if let environment = environment {
        task.environment = environment
    }

    let pipe = Pipe()
    task.standardOutput = pipe
    task.standardError = pipe
    task.launch()
    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output = String(data: data, encoding: .utf8) ?? ""
    task.waitUntilExit()
    return (output, task.terminationStatus)
}

```