2014-11-17 5 views
41

मैं अपनी सीआई बैश स्क्रिप्ट को तेज़ी से बदलना चाहता हूं। मैं समझ नहीं सामान्य टर्मिनल कमांड आह्वान करने के लिए कैसे इस तरह के ls के रूप में या xcodebuildमैं एक स्विफ्ट स्क्रिप्ट में टर्मिनल कमांड कैसे चला सकता हूं? (उदा। 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 .... 

उत्तर

76

आप स्विफ्ट कोड में आदेश आउटपुट का उपयोग नहीं करते हैं, तो निम्न पर्याप्त होगा:

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

अपडेट किया गया: Swift3/Xcode8

+0

यह वास्तव में बहुत साफ दिखता है। – Robert

+1

'एनएसटीस्क' का नाम बदलकर 'प्रक्रिया' – Mateusz

+0

कर रहा है, मैं इसका उपयोग कैसे कर सकता हूं (जैसे सफारी)?/open -a applicationname कभी काम नहीं करता है। – dylan

21

समस्या यहाँ है कि आप मिश्रण और बैश और स्विफ्ट से मेल नहीं कर सकते हैं। आप पहले ही जानते हैं कि कमांड लाइन से स्विफ्ट स्क्रिप्ट कैसे चलाएं, अब आपको स्विफ्ट में शैल कमांड निष्पादित करने के तरीकों को जोड़ने की आवश्यकता है। PracticalSwift ब्लॉग से सारांश में:

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 
} 

निम्नलिखित स्विफ्ट कोड तर्क और उसके बाद उत्पादन परिणाम के साथ xcodebuild निष्पादित करेंगे।

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

खोज निर्देशिका सामग्री (जो क्या ls बैश में करता है), मैं NSFileManager उपयोग करने का सुझाव और सीधे निर्देशिका स्कैनिंग स्विफ्ट में, बैश उत्पादन है, जो एक दर्द पार्स करने के लिए हो सकता है के बजाय का सवाल है।

+0

महान (String में परिवर्तन से निपटने) - मैं इस संकलन करने के लिए कुछ संपादन करने के हालांकि, मुझे 'खोल ("ls", [])' - ''NSInvalidArgumentException' का आह्वान करने का प्रयास करते समय रनटाइम अपवाद मिल रहा है, कारण: 'लॉन्च पथ सुलभ नहीं है' 'कोई विचार? – Robert

+3

एनएसटीस्क * निष्पादन योग्य नहीं है (पर्यावरण से आपके पैथ का उपयोग करके) खोल करता है। लॉन्च पथ एक पूर्ण पथ होना चाहिए (उदा। "/ Bin/ls") या वर्तमान कार्यशील निर्देशिका से संबंधित पथ होना चाहिए। –

+0

http: // stackoverflow।कॉम/प्रश्न/386783/nstask-not-picking-up-path-from-the-users-environment PATH मूल रूप से एक खोल की अवधारणा है और पहुंच योग्य नहीं है। – Legoless

8

पूर्ण Legoless के उत्तर के आधार पर स्क्रिप्ट

#!/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"]) 
13
के लिए

यदि आप कमांड कॉल करने के लिए बैश पर्यावरण का उपयोग करना चाहते हैं तो निम्न बैश फ़ंक्शन का उपयोग करें जो Legoless के एक निश्चित संस्करण का उपयोग करता है। मुझे शैल फ़ंक्शन के परिणाम से पिछली नई लाइन को हटाना पड़ा।

स्विफ्ट 3.0: (Xcode8)

import Foundation 

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

उदाहरण के लिए वर्तमान कार्यशील निर्देशिका की वर्तमान काम कर Git शाखा पाने के लिए:

let currentBranch = bash("git", arguments: ["describe", "--contains", "--all", "HEAD"]) 
print("current branch:\(currentBranch)") 
16

उपयोगिता समारोह स्विफ्ट 3.0 में

यह कार्य समाप्ति स्थिति भी देता है और पूरा होने की प्रतीक्षा करता है।

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

'आयात फाउंडेशन' गायब – Binarian

+2

दुख की बात है, आईओएस के लिए नहीं। – Raphael

0

स्विफ्ट 4.0 के लिए स्विफ्ट 3 के लिए Rintaro और Legoless के जवाब मिश्रण

@discardableResult 
func shell(_ args: String...) -> String { 
    let task = Process() 
    task.launchPath = "/usr/bin/env" 
    task.arguments = args 

    let pipe = Pipe() 
    task.standardOutput = pipe 

    task.launch() 
    task.waitUntilExit() 

    let data = pipe.fileHandleForReading.readDataToEndOfFile() 

    guard let output: String = String(data: data, encoding: .utf8) else { 
     return "" 
    } 
    return output 
} 
0

अद्यतन कर रहा है

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) 
} 
संबंधित मुद्दे

 संबंधित मुद्दे