如何向子进程管道传输数据?Rust实现问题及跨平台咨询
问题描述
我尝试在子进程中运行脚本,希望避免将脚本写入磁盘再执行。想要复现以下Shell命令的效果:
echo "console.log(42)" | node # 输出:42
我编写了如下Rust代码,但程序没有任何输出且子进程始终不退出:
use std::process::{Command, Stdio}; fn main() { let mut command = Command::new("node"); command.stderr(Stdio::inherit()); command.stdout(Stdio::inherit()); command.stdin(Stdio::piped()); let mut child = command.spawn().unwrap(); let mut stdin = child.stdin.take().unwrap(); stdin.write("console.log(42)".as_bytes()).unwrap(); child.wait().unwrap(); }
另外,这种方式在Windows系统上是否可行?还是仅适用于UNIX系统?
编辑补充:我希望保持stdin处于开放状态,以便在初始化脚本后与进程收发消息。
解决方案
问题根源
Node.js通过stdin接收脚本时,默认会等待输入的**结束标记(EOF)**才会执行代码并退出。你的代码只向子进程stdin写入了内容,但未关闭stdin或发送EOF,导致Node.js一直阻塞等待更多输入,因此子进程不退出也无输出。
分场景处理
场景1:执行脚本后退出
如果仅需执行单次脚本后让子进程退出,只需在写入内容后关闭stdin,触发Node.js的EOF检测:
use std::process::{Command, Stdio}; fn main() { let mut command = Command::new("node"); command.stderr(Stdio::inherit()); command.stdout(Stdio::inherit()); command.stdin(Stdio::piped()); let mut child = command.spawn().unwrap(); { let mut stdin = child.stdin.take().unwrap(); stdin.write_all("console.log(42)".as_bytes()).unwrap(); // 离开作用域时stdin自动被drop,关闭管道并发送EOF给Node.js } child.wait().unwrap(); }
场景2:保持stdin开放以持续交互
如果要保持stdin开放、后续与子进程收发消息,不能直接调用child.wait()(会阻塞主线程),需用多线程或异步IO处理输入输出并发:
多线程实现示例
use std::io::{self, Write}; use std::process::{Command, Stdio}; use std::thread; fn main() { let mut command = Command::new("node"); command.stderr(Stdio::inherit()); command.stdout(Stdio::inherit()); command.stdin(Stdio::piped()); let mut child = command.spawn().unwrap(); // 将stdin移交子线程处理,避免阻塞主线程 let mut stdin = child.stdin.take().unwrap(); thread::spawn(move || { // 写入初始化脚本 writeln!(stdin, "console.log(42);").unwrap(); // 持续读取控制台输入并转发给Node进程 let mut input = String::new(); while io::stdin().read_line(&mut input).unwrap() > 0 { writeln!(stdin, "{}", input.trim()).unwrap(); input.clear(); } }); // 主线程等待子进程结束 child.wait().unwrap(); }
同时,Node.js侧需要编写持续监听stdin的代码,否则只会处理一次输入就退出,例如初始化脚本可以写为:
console.log(42); process.stdin.on('data', (data) => { const code = data.toString().trim(); try { eval(code); } catch (e) { console.error(e); } });
Windows兼容性
这种通过stdin管道传递脚本的方式完全支持Windows系统:
- Rust的
std::process::Command的stdin管道是跨平台实现的,Windows上可正常创建并写入子进程标准输入。 - Node.js在Windows上的行为与UNIX一致,无论是单次执行还是持续交互模式,都能通过stdin接收脚本代码并正常工作。
内容的提问来源于stack exchange,提问作者David Alsh
相关产品推荐
相关产品推荐

