Swift スクリプトでターミナル コマンドを実行するにはどうすればよいですか? (例: xcodebuild) 質問する

Swift スクリプトでターミナル コマンドを実行するにはどうすればよいですか? (例: xcodebuild) 質問する

lsCI bashスクリプトをswiftに置き換えたいのですが、またはなどの通常のターミナルコマンドを呼び出す方法がわかりません。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 ....

ベストアンサー1

コマンドライン引数をコマンドラインとまったく同じように使用したい場合 (すべての引数を分離せずに)、次の操作を試してください。

(この回答はLegoLessの回答を改良したもので、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")

更新された/より安全な関数呼び出し 10/23/21:上記のシェル コマンドで実行時エラーが発生する可能性があります。その場合は、以下の更新された呼び出しに切り替えてみてください。新しいシェル コマンドの周囲に do catch ステートメントを使用する必要がありますが、これにより、予期しないエラーをキャッチする方法の検索にかかる時間も節約できます。

説明: task.launch() はスロー関数ではないため、キャッチできず、呼び出されるとアプリがクラッシュするだけであることが時々ありました。インターネットでいろいろ調べた結果、Process クラスでは task.launch() が廃止され、代わりに新しい関数 task.run() が採用されていることがわかりました。この関数はアプリをクラッシュさせることなくエラーを適切にスローします。更新されたメソッドの詳細については、以下を参照してください。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
}

例:

// 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")

注: を使用し、結果を使用しない最後のケースではtry?、 としてマークされているにもかかわらず、何らかの理由でコンパイラーは警告を出します@discardableResult。これは の場合にのみ発生しtry?、ブロックtrydo-try-catchまたはスロー関数内からは発生しません。いずれの場合も、無視しても問題ありません。

おすすめ記事