Swift子进程readLine挂起

rkkpypqq  于 2022-12-10  发布在  Swift
关注(0)|答案(1)|浏览(161)

我有以下Swift脚本(名为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")
}

我希望输出为:

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

实际输出为:

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

readLine上的子进程挂起。根据Swift documentation,如果task.standardInput没有设置,那么它应该从父进程继承。
我的主要目标是能够允许用户通过终端向子进程输入。最好不需要父进程也能输入。
为什么子进程不能像父进程一样在按回车键后收到输入的文本?有什么办法解决这个问题吗?

pod7payv

pod7payv1#

我通过使用一个临时管道对象和一些直接内容阅读来解决这个问题。

#!/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")
}

相关问题