You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 17:11:18