1

I have the following Code:

func syncShellExec(path: String, args: [String] = []) {
    let process            = Process()
    process.launchPath     = "/bin/bash"
    process.arguments      = [path] + args
    let outputPipe         = Pipe()
    let filelHandler       = outputPipe.fileHandleForReading
    process.standardOutput = outputPipe
    process.launch()

    filelHandler.readabilityHandler = { pipe in
        let data = pipe.availableData
        if let line = String(data: data, encoding: String.Encoding.utf8) {
            DispatchQueue.main.sync {
                self.output_window.string += line
                self.output_window.scrollToEndOfDocument(nil)
            }
        } else {
            print("Error decoding data: \(data.base64EncodedString())")
        }
    }
    process.waitUntilExit()
    filelHandler.readabilityHandler = nil
}

If the amount of round about 330.000 Characters is reached the output stopped immediately. Is there a way to increase the Buffer for this Operation?

Sascha7777
  • 89
  • 8
  • I assume that the problem is that the process terminates before all data has been read from the pipe. See https://stackoverflow.com/a/52336340/1187415 for a possible solution. – Martin R Sep 12 '19 at 11:58

1 Answers1

2

There are two problems:

  • The process may terminate before all data has been read from the pipe.
  • Your function blocks the main thread, so that the UI eventually freezes.

Similarly as in How can I tell when a FileHandle has nothing left to be read? you should wait asynchronously for the process to terminate, and also wait for “end-of-file” on the pipe:

func asyncShellExec(path: String, args: [String] = []) {
    let process            = Process()
    process.launchPath     = "/bin/bash"
    process.arguments      = [path] + args
    let outputPipe         = Pipe()
    let filelHandler       = outputPipe.fileHandleForReading
    process.standardOutput = outputPipe
    process.launch()

    let group = DispatchGroup()
    group.enter()
    filelHandler.readabilityHandler = { pipe in
        let data = pipe.availableData
        if data.isEmpty { // EOF
            filelHandler.readabilityHandler = nil
            group.leave()
            return
        }

        if let line = String(data: data, encoding: String.Encoding.utf8) {
            DispatchQueue.main.sync {
                self.output_window.string += line
                self.output_window.scrollToEndOfDocument(nil)
            }
        } else {
            print("Error decoding data: \(data.base64EncodedString())")
        }
    }

    process.terminationHandler = { process in
        group.wait()
        DispatchQueue.main.sync {
            // Update UI that process has finished.
        }
    }
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382