Home > Blockchain >  Swift child process readLine hangs
Swift child process readLine hangs

Time:12-06

I have the following Swift script (named test.swift):

#!/usr/bin/swift
import Foundation

print("\(CommandLine.arguments.count)")
if (CommandLine.arguments.count == 1) {
    let task = Process()
    task.arguments = [ "-c", "./test.swift child" ]
    task.launchPath = "/bin/zsh"

    do {
        try task.run()
        task.waitUntilExit()
    } catch {
        print(error)
    }
} else {
    print("Input requested:")
    print(readLine() ?? "NULL")
}

I expect the output to be:

1
2
Input requested:
<user inputs some text> <user presses enter>
<echo text>

The actual output is:

1
2
Input requested:
<user inputs some text> <user presses enter>

The child process hangs on readLine. According to the Swift documentation if task.standardInput is not set, then it should inherit from the parent process.

My main goal in to be able to allow the user to input through the terminal to the child process. Preferably without the need for the parent the process the input as well.

Why does the child process not receive the inputted text upon pressing enter like the parent process would? And is there any way to solve this?

CodePudding user response:

I solved it by using a temporary pipe object and some direct content reading .

#!/usr/bin/swift

import Foundation

print("\(CommandLine.arguments.count)")
if (CommandLine.arguments.count == 1) {
    let task = Process()
    task.arguments = [ "-c", "./test.swift child" ]
    task.launchPath = "/bin/zsh"

    let stdin_pipe = Pipe()
    task.standardInput = stdin_pipe.fileHandleForReading

    let stdin_queue = DispatchQueue(label: "test.serial.queue")
    let stdin_src = DispatchSource.makeReadSource(fileDescriptor: STDIN_FILENO, queue: stdin_queue)

    do {
        try task.run()

        var stdin_line = ""
        stdin_src.setEventHandler(handler: {
            var cstr = [CChar](repeating: 0, count: 256)
            if read(STDIN_FILENO, &cstr, 256) > 0 {
                stdin_line.append(String(cString: cstr))
            }
        })

        stdin_src.resume()
        while (task.isRunning) {
            if stdin_line.count > 0 {
                try stdin_pipe.fileHandleForWriting.write(contentsOf: stdin_line.data(using: .utf8)!)
            }
        }
    } catch {
        print(error)
    }
} else {
    print("Input requested:")
    print(readLine() ?? "NULL")
}
  • Related