I am working on a Swift app that interacts with external binaries (via NSTask) and returns the output as an array of strings, for each line.
When calling the executeCommand function multiple times, commands start failing to return expected data.
In the example Playground below I'm polling diskutil for volume names.
In the Debug Area the first response I get is:
- Not applicable (no file system)
- Macintosh HD
- Unable to obtain volume name
- Unable to obtain volume name
- Unable to obtain volume name
Simply re-running the Playground results in:
- Not applicable (no file system)
- Unable to obtain volume name <-- What happened to Macintosh HD?
- Unable to obtain volume name
- Unable to obtain volume name
Unable to obtain volume name
import Cocoa func executeCommand(launchPath: String, arguments: [String], additionalDelay: Int=0) -> [String] { let outputPipe = NSPipe() var outputArray = [String]() let task = NSTask() task.launchPath = launchPath task.arguments = arguments task.standardOutput = outputPipe outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify() NSNotificationCenter.defaultCenter().addObserverForName(NSFileHandleDataAvailableNotification, object: outputPipe.fileHandleForReading , queue: nil) { notification in let output = outputPipe.fileHandleForReading.availableData let outputString = String(data: output, encoding: NSUTF8StringEncoding) ?? "" outputArray = outputString.componentsSeparatedByCharactersInSet(.newlineCharacterSet()) outputPipe.fileHandleForReading.waitForDataInBackgroundAndNotify() } task.launch() sleep(UInt32(additionalDelay)) // Additional delay task.waitUntilExit() // Remove last empty line from output array. if outputArray.count > 0 { outputArray.removeLast() } return outputArray } // Example usage // Output volume name from provided disk identifier func volumeName(identifier: String) -> String { let volumeNameCommand = "/usr/sbin/diskutil info \(identifier) | awk '/Volume Name:/' | sed 's/Volume Name://g'| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//'" let volumeNameOutput = executeCommand("/bin/bash", arguments: ["-c", volumeNameCommand]) var volumeName = "Unable to obtain volume name" if volumeNameOutput.count > 0 { volumeName = volumeNameOutput[0] } return volumeName } let identifiers = ["/dev/disk0","/dev/disk1","/dev/disk2","/dev/disk3","/dev/disk4"] for identifier in identifiers { print(volumeName(identifier)) }
I really need consistent results, but don't understand where I'm going wrong.
Any help would be greatly appreciated!