如何在Bash变量中捕获运行中Swift服务器进程的输出?
解决Swift后台服务器URL捕获到Bash变量的问题
问题分析
你的推测完全正确:Bash的命令替换(`...`或$(...))会等待目标进程完全退出后,才会读取其全部输出并完成变量赋值。而你的服务器调用server.wait()后持续阻塞运行,导致输出流未关闭,无法完成变量赋值。另外,export SERVER_URL=... &的方式无效,是因为这条export命令在后台子Shell中执行,当前Shell无法访问子Shell的环境变量。
解决方法
方法1:进程替换+实时读取第一行输出
利用Bash的进程替换功能,将服务器输出直接传给read命令,同时让服务器后台运行。这样read会立即捕获服务器打印的第一行URL,无需等待进程退出:
# 读取服务器输出的第一行到变量,同时让服务器后台运行 read -r SERVER_URL < <(.build/release/server run -c Tests/files/TestConfig3 2>&1 &) # 导出变量供其他程序使用 export SERVER_URL
2>&1:将标准错误重定向到标准输出,避免服务器错误信息干扰URL捕获< <(...):进程替换,把服务器的输出作为read的输入源&:让服务器进程后台运行,不阻塞当前Shell
方法2:修改Swift程序强制刷新输出
默认情况下,stdout在非终端环境(如管道、进程替换)下会采用块缓冲,print的内容可能不会立即输出。可以在print后强制刷新标准输出,确保URL能被及时捕获:
@main struct MyApplication { static func main() throws { let server = try VoodooServer { Endpoints.config } print(server.url.absoluteString) fflush(stdout) // 强制刷新标准输出,立即输出内容 server.wait() } }
将此修改和方法1结合使用,能确保URL被可靠捕获。
方法3:临时文件中转输出
如果上述方法有兼容性问题,可以用临时文件作为输出中转:
# 创建临时文件 TEMP_FILE=$(mktemp) # 启动服务器并将输出重定向到临时文件,后台运行 .build/release/server run -c Tests/files/TestConfig3 > "$TEMP_FILE" 2>&1 & # 短暂等待确保URL已写入文件(时间可根据实际情况调整) sleep 0.1 # 读取临时文件第一行到变量 read -r SERVER_URL < "$TEMP_FILE" # 导出变量 export SERVER_URL # 删除临时文件 rm "$TEMP_FILE"
验证
执行完上述任一方法后,用以下命令验证变量是否正确获取:
echo $SERVER_URL
内容的提问来源于stack exchange,提问作者drekka
相关产品推荐
相关产品推荐

