Avatar
@swift-5.3.3 import Foundation extension Process { struct RunResult { var output: Data var error: Data var status: Int32 } static func which(_ i: Int) throws -> RunResult { let p = Process() p.executableURL = URL(fileURLWithPath: "/usr/bin/which") p.arguments = ["which"] let g = DispatchGroup() var outData = Data() let outPipe = Pipe() p.standardOutput = outPipe g.enter() outPipe.fileHandleForReading.readabilityHandler = { (handle) in let availableData = handle.availableData outData.append(availableData) print("[\(i)] stdout \(availableData)") if availableData.isEmpty { outPipe.fileHandleForReading.readabilityHandler = nil g.leave() } } var errData = Data() let errPipe = Pipe() p.standardError = errPipe g.enter() errPipe.fileHandleForReading.readabilityHandler = { (handle) in let availableData = handle.availableData errData.append(availableData) print("[\(i)] stderr \(availableData)") if availableData.isEmpty { errPipe.fileHandleForReading.readabilityHandler = nil g.leave() } } try p.run() p.waitUntilExit() print("[\(i)] process end") guard case .success = g.wait(timeout: .now()+3) else { fatalError("[\(i)] timeout") } print("[\(i)] wait end") let status = p.terminationStatus let result = RunResult(output: outData, error: errData, status: status) print("[\(i)] end output=\(result.output) error=\(result.error)") return result } } DispatchQueue.concurrentPerform(iterations: 3) { i in _ = try! Process.which(i) } print("end")