Skip to main content
On this page

创建子进程

概念 Jump to heading

  • Deno 可以通过 Deno.Command 启动子进程。
  • 启动子进程需要 --allow-run 权限。
  • 启动的子进程不在安全沙箱中运行。
  • 通过 stdinstdoutstderr 流与子进程进行通信。

简单示例 Jump to heading

该示例相当于从命令行运行 echo "Hello from Deno!"

subprocess_simple.ts
// 定义用于创建子进程的命令
const command = new Deno.Command("echo", {
  args: [
    "Hello from Deno!",
  ],
});

// 创建子进程并收集输出
const { code, stdout, stderr } = await command.output();

console.assert(code === 0);
console.log(new TextDecoder().decode(stdout));
console.log(new TextDecoder().decode(stderr));

运行它:

$ deno run --allow-run=echo ./subprocess_simple.ts
Hello from Deno!

安全性 Jump to heading

创建子进程需要 --allow-run 权限。请注意,子进程不在 Deno 沙箱中运行,因此具有与您自己从命令行运行命令时相同的权限。

与子进程通信 Jump to heading

默认情况下,当您使用 Deno.Command() 时,子进程继承父进程的 stdinstdoutstderr。如果您想与启动的子进程进行通信,您必须使用 "piped" 选项。

管道输出到文件 Jump to heading

该示例相当于在 bash 中运行 yes &> ./process_output

subprocess_piping_to_files.ts
import {
  mergeReadableStreams,
} from "jsr:@std/streams@1.0.0-rc.4/merge-readable-streams";

// 创建要附加到进程的文件
const file = await Deno.open("./process_output.txt", {
  read: true,
  write: true,
  create: true,
});

// 启动进程
const command = new Deno.Command("yes", {
  stdout: "piped",
  stderr: "piped",
});

const process = command.spawn();

// 示例:将 stdout 和 stderr 合并并发送到文件
const joined = mergeReadableStreams(
  process.stdout,
  process.stderr,
);

// 返回一个 Promise,直到进程被终止/关闭时解析
joined.pipeTo(file.writable).then(() => console.log("管道合并完成"));

// 手动停止进程,“yes” 将永远不会自行结束
setTimeout(() => {
  process.kill();
}, 100);

运行它:

$ deno run --allow-run=yes --allow-read=. --allow-write=. ./subprocess_piping_to_file.ts

使用便捷方法读取子进程输出 Jump to heading

在使用启动的子进程时,您可以对 stdoutstderr 流使用便捷方法,轻松收集和解析输出。这些方法类似于 Response 对象上可用的方法:

subprocess_convenience_methods.ts
const command = new Deno.Command("deno", {
  args: [
    "eval",
    "console.log(JSON.stringify({message: 'Hello from subprocess'}))",
  ],
  stdout: "piped",
  stderr: "piped",
});

const process = command.spawn();

// 使用便捷方法收集输出
const stdoutText = await process.stdout.text();
const stderrText = await process.stderr.text();

console.log("stdout:", stdoutText);
console.log("stderr:", stderrText);

// 等待进程完成
const status = await process.status;
console.log("退出码:", status.code);

便捷的 spawn 函数 Jump to heading

Caution

Deno.spawn(), Deno.spawnAndWait(), 和 Deno.spawnAndWaitSync() 是 Deno 2.7 版本引入的 不稳定 API。它们可能会在稳定之前发生变化。

自 Deno 2.7 起,提供了三个简洁的函数,它们是 Deno.Command 的简写替代:

  • Deno.spawn(command, args, options?) — 启动子进程并返回一个 ChildProcess(等同于 new Deno.Command(cmd, { args }).spawn()
  • Deno.spawnAndWait(command, args, options?) — 启动子进程并 返回一个 promise,解析为 CommandOutput(等同于 new Deno.Command(cmd, { args }).output()
  • Deno.spawnAndWaitSync(command, args, options?) — 同步版本, 会阻塞直到子进程完成
spawn_examples.ts
// 启动子进程
const child = Deno.spawn("echo", ["hello"]);

// 启动并等待输出
const output = await Deno.spawnAndWait("git", ["status"]);
console.log(new TextDecoder().decode(output.stdout));

// 使用选项启动
const formatted = Deno.spawn("deno", ["fmt", "--check"], {
  stdout: "inherit",
});

// 同步执行
const result = Deno.spawnAndWaitSync("echo", ["done"]);

这些函数接受命令和参数作为分开的参数,相较于 Deno.Command 构造函数的选项模式更加易读。

输出流的便捷方法 Jump to heading

可用的便捷方法包括:

  • .text() - 返回 UTF-8 编码的字符串输出
  • .bytes() - 返回 Uint8Array 类型的输出
  • .arrayBuffer() - 返回 ArrayBuffer 类型的输出
  • .json() - 解析输出为 JSON 并返回该对象
subprocess_json_parsing.ts
const command = new Deno.Command("deno", {
  args: ["eval", "console.log(JSON.stringify({name: 'Deno', version: '2.0'}))"],
  stdout: "piped",
});

const process = command.spawn();

// 直接解析 JSON 输出
const jsonOutput = await process.stdout.json();
console.log("解析后的 JSON:", jsonOutput); // { name: "Deno", version: "2.0" }

await process.status;

你找到了你需要的东西吗?

编辑此页面
隐私政策