Execute a terminal command from a Cocoa app

后端 未结 12 2301
既然无缘
既然无缘 2020-11-22 06:34

How can I execute a terminal command (like grep) from my Objective-C Cocoa application?

12条回答
  •  谎友^
    谎友^ (楼主)
    2020-11-22 06:54

    Here's how to do it in Swift

    Changes for Swift 3.0:

    • NSPipe has been renamed Pipe

    • NSTask has been renamed Process


    This is based on inkit's Objective-C answer above. He wrote it as a category on NSString — For Swift, it becomes an extension of String.

    extension  String.runAsCommand()  ->  String

    extension String {
        func runAsCommand() -> String {
            let pipe = Pipe()
            let task = Process()
            task.launchPath = "/bin/sh"
            task.arguments = ["-c", String(format:"%@", self)]
            task.standardOutput = pipe
            let file = pipe.fileHandleForReading
            task.launch()
            if let result = NSString(data: file.readDataToEndOfFile(), encoding: String.Encoding.utf8.rawValue) {
                return result as String
            }
            else {
                return "--- Error running command - Unable to initialize string from file data ---"
            }
        }
    }
    

    Usage:

    let input = "echo hello"
    let output = input.runAsCommand()
    print(output)                        // prints "hello"
    

        or just:

    print("echo hello".runAsCommand())   // prints "hello" 
    

    Example:

    @IBAction func toggleFinderShowAllFiles(_ sender: AnyObject) {
    
        var newSetting = ""
        let readDefaultsCommand = "defaults read com.apple.finder AppleShowAllFiles"
    
        let oldSetting = readDefaultsCommand.runAsCommand()
    
        // Note: the Command results are terminated with a newline character
    
        if (oldSetting == "0\n") { newSetting = "1" }
        else { newSetting = "0" }
    
        let writeDefaultsCommand = "defaults write com.apple.finder AppleShowAllFiles \(newSetting) ; killall Finder"
    
        _ = writeDefaultsCommand.runAsCommand()
    
    }
    

    Note the Process result as read from the Pipe is an NSString object. It might be an error string and it can also be an empty string, but it should always be an NSString.

    So, as long as it's not nil, the result can cast as a Swift String and returned.

    If for some reason no NSString at all can be initialized from the file data, the function returns an error message. The function could have been written to return an optional String?, but that would be awkward to use and wouldn't serve a useful purpose because it's so unlikely for this to occur.

提交回复
热议问题