2

I am using the following code to execute a bash command from Swift:

func runCommand(cmd : String, args : String...) -> (output: [String], error: [String], exitCode: Int32) {

    var output : [String] = []
    var error : [String] = []

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

    let outpipe = NSPipe()
    task.standardOutput = outpipe
    let errpipe = NSPipe()
    task.standardError = errpipe

    task.launch()

    let outdata = outpipe.fileHandleForReading.readDataToEndOfFile()
    if var string = String.fromCString(UnsafePointer(outdata.bytes)) {
        string = string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
        output = string.componentsSeparatedByString("\n")
    }

    let errdata = errpipe.fileHandleForReading.readDataToEndOfFile()
    if var string = String.fromCString(UnsafePointer(errdata.bytes)) {
        string = string.stringByTrimmingCharactersInSet(NSCharacterSet.newlineCharacterSet())
        error = string.componentsSeparatedByString("\n")
    }

    task.waitUntilExit()
    let status = task.terminationStatus

    return (output, error, status)
}

Credit: Get terminal output after a command swift

When I run the function with the following code:

runCommand("/sbin/ifconfig", args: "en1", "|", "grep", "ether")

To simulate running the following command from the shell:

ifconfig en1 | grep ether

That will result in some output like this:

ether xx:xx:xx:xx:xx:xx 

I get the following error:

ifconfig: |: bad value

I'm guessing that this is because the commands aren't being combined and the "|" symbol is being interpreted as a direct argument to ifconfig.

Is there a way to simulate this type of shell behaviour (the usage of the "|" symbol to filter the output of a command) from within Swift?

Community
  • 1
  • 1
SamTebbs33
  • 5,507
  • 3
  • 22
  • 44
  • 1
    You need to set the first command's output pipe to the second command's input pipe. (You need one `NSTask` object for the `/sbin/ifconfig` command, and pipe that output to the input of another `NSTask` for the `grep` command.) – nhgrif Apr 09 '15 at 21:58
  • 3
    Using the shell does also work: `runCommand("/bin/sh", args: "-c", "/sbin/ifconfig en1 | grep ether")`. – Btw, the code looks familiar http://stackoverflow.com/a/29519615/1187415 :) – Martin R Apr 09 '15 at 22:09
  • @MartinR Edited the original post to give credit to the code's author. I will try these two methods, thanks! – SamTebbs33 Apr 09 '15 at 22:15
  • 1
    NSTask will automatically wrap all arguments in quotes to allow spaces, etc. in the parameters. Using `/bin/sh` as Martin R suggested is the only method then but you have to make sure yourself, that parameters are quoted/escaped as needed! – hexerei software Apr 09 '15 at 22:22
  • @SamTebbs33 which solution did you go on with? – Thellimist Dec 09 '15 at 23:06
  • @Entei I went with the suggestion by nhgrif, If I remember correctly. – SamTebbs33 Dec 10 '15 at 12:32
  • Perhaps you should self-answer and accept, or delete the question. – miken32 Mar 03 '16 at 03:42
  • @nhgrif Used your comment as an answer – SamTebbs33 Mar 03 '16 at 19:08

1 Answers1

0

Solved with nhgrif's comment: Combine bash commands with each other

Community
  • 1
  • 1
SamTebbs33
  • 5,507
  • 3
  • 22
  • 44
  • 3 things, 1. Link the comment in the answer. 2. Ping the user stating that you have converted his comment to an answer 3. (optional) Make the ans community wiki as it is not your effort – Bhargav Rao Mar 03 '16 at 13:03
  • @BhargavRao You can't tag (what I assume you mean by "ping") users in an answer. How do I link a comment and how do I answer on behalf of the community? – SamTebbs33 Mar 03 '16 at 18:26
  • 1
    You can ping the user in the comments above. The timestamp of the comment gives the link to the comment. – Bhargav Rao Mar 03 '16 at 18:27