Swift子进程readLine挂起问题:原因排查与解决咨询
子进程无法接收终端输入的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()时无法获取终端输入,即使文档说明未设置task.standardInput时子进程应继承父进程标准输入。需要让用户直接向子进程输入内容,无需父进程处理输入。
原因分析
问题出在通过zsh -c间接启动子进程的方式上:zsh在执行-c参数指定的命令时,默认不会正确将自身的终端标准输入转发给子进程,导致子进程的readLine()无法读取到用户输入。
解决办法
方法1:直接启动Swift脚本(推荐)
跳过zsh中转,直接将Process的启动路径设为脚本本身,前提是已给脚本添加可执行权限(执行chmod +x test.swift):
let task = Process() task.arguments = ["child"] task.launchPath = "./test.swift"
这种方式下子进程直接继承父进程的终端输入,readLine()可以正常获取用户输入。
方法2:强制zsh传递输入
如果必须通过zsh启动,可使用exec命令让zsh替换自身为目标脚本进程,从而完整继承标准输入:
let task = Process() task.arguments = [ "-c", "exec ./test.swift child" ] task.launchPath = "/bin/zsh"
exec会让zsh进程被脚本进程替代,而非创建子进程,输入就能正确传递到脚本的readLine()。
内容的提问来源于stack exchange,提问作者Arzana
相关产品推荐
相关产品推荐

