ios - titel - title tag




Wie führe ich einen Terminal-Befehl in einem schnellen Skript aus?(zB xcodebuild) (6)

Aktualisierung für Swift 4.0 (Umgang mit Änderungen an String )

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)!
    if output.count > 0 {
        //remove newline character.
        let lastIndex = output.index(before: output.endIndex)
        return String(output[output.startIndex ..< lastIndex])
    }
    return output
}

func bash(command: String, arguments: [String]) -> String {
    let whichPathForCommand = shell(launchPath: "/bin/bash", arguments: [ "-l", "-c", "which \(command)" ])
    return shell(launchPath: whichPathForCommand, arguments: arguments)
}

Ich möchte meine CI-Bash-Skripte durch swift ersetzen. Ich kann nicht herausfinden, wie man normalen Terminalbefehl wie ls oder 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 ....

Das Problem hier ist, dass Sie Bash and Swift nicht mischen können. Sie wissen bereits, wie Sie Swift-Skript über die Befehlszeile ausführen. Jetzt müssen Sie die Methoden zum Ausführen von Shell-Befehlen in Swift hinzufügen. Zusammenfassend aus dem 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
}

Der folgende Swift-Code führt xcodebuild mit Argumenten aus und gibt dann das Ergebnis aus.

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

NSFileManager den Inhalt des Verzeichnisses zu durchsuchen (was in Bash der Fall ist), schlage ich vor, NSFileManager und das Verzeichnis direkt in Swift zu scannen, anstatt mit der Bash-Ausgabe zu arbeiten. Das kann sehr mühsam sein.


Vollständiges Skript basierend auf Legoless 'Antwort

#!/usr/bin/env xcrun swift

import Foundation

func printShell(launchPath: String, arguments: [AnyObject] = []) {
    let output = shell(launchPath, arguments:arguments)

    if (output != nil) {
        println(output!)
    }
}

func shell(launchPath: String, arguments: [AnyObject] = []) -> String? {

    let task = NSTask()
    task.launchPath = launchPath
    task.arguments = arguments

    let pipe = NSPipe()
    task.standardOutput = pipe
    task.launch()

    let data = pipe.fileHandleForReading.readDataToEndOfFile()
    let output: String? = NSString(data: data, encoding: NSUTF8StringEncoding)

    return output
}

// > ls
// > ls -a -g
printShell("/bin/ls")
printShell("/bin/ls", arguments:["-a", "-g"])

Wenn Sie Befehlszeilenargumente "genau" wie in der Befehlszeile verwenden möchten (ohne alle Argumente zu trennen), versuchen Sie Folgendes.

(Diese Antwort verbessert die Antwort von LegoLess und kann in Swift 4 Xcode 9.3 verwendet werden)

func shell(_ command: String) -> String {
    let task = Process()
    task.launchPath = "/bin/bash"
    task.arguments = ["-c", command]

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

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

    return output
}

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

Wenn Sie keine Befehlsausgaben in Swift-Code verwenden, wäre Folgendes ausreichend:

#!/usr/bin/env swift

import Foundation

@discardableResult
func 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")

Aktualisiert: für Swift3 / Xcode8


Dienstprogrammfunktion in Swift 3.0

Dies gibt auch den Beendigungsstatus der Aufgaben zurück und wartet auf den Abschluss.

func shell(launchPath: String, arguments: [String] = []) -> (String? , Int32) {
    let task = Process()
    task.launchPath = launchPath
    task.arguments = arguments

    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)
}




xcodebuild