从子进程流式传输标准输出

Stream stdout from subprocess

我 运行 一个 Docker 在 Deno 中构建为一个子进程,并且希望将标准输出流式传输到父标准输出 (Deno.stdout),以便它立即输出。

我怎样才能做到这一点?

目前我有以下内容,但在子流程完成之前它不会输出任何内容。

const p = Deno.run({
  cmd: ['docker', 'build', '.'],
  stdout: 'piped'
});

const stdout = await p.output();
await Deno.stdout.write(stdout);

p 代表进程,Deno.run returns the process state 在 return 上(不是标准输出):

console.log(await p.status());
// { success: true, code: 0 }

由于您正在等待状态,stdout 将不会流式传输输出,直到该过程完成。

尝试 using the process 像这样:

const p = Deno.run({ cmd, stderr: 'piped', stdout: 'piped' });
const [status, stdout, stderr] = await Promise.all([
  p.status(),
  p.output(),
  p.stderrOutput()
]);

console.log(new TextDecoder().decode(stdout)); // since it's returned as UInt8Array

p.close();

但它仍然会等到子进程完成。

你已经不远了;您只需要在等待该过程之前开始管道输出过程。您还可以进行一些其他优化,例如使用 Deno.copy 将子进程的输出通过管道传输到主进程的标准输出,而无需在内存中复制内容。

import { copy } from "https://deno.land/std@0.104.0/io/util.ts";

const cat = Deno.run({
  cmd: ["docker", "build", "--no-cache", ".", "-t", "foobar:latest"],
  cwd: "/path/to/your/project",
  stdout: "piped",
  stderr: "piped",
});

copy(cat.stdout, Deno.stdout);
copy(cat.stderr, Deno.stderr);

await cat.status();
console.log("Done!");

如果你想在每一行前面加上它来自的进程的名称(当你有多个子进程时很有用运行,你可以创建一个使用标准库的简单函数readLines功能和一个文本编码器来做到这一点

import { readLines } from "https://deno.land/std@0.104.0/io/mod.ts";
import { writeAll } from "https://deno.land/std@0.104.0/io/util.ts";

async function pipeThrough(
  prefix: string,
  reader: Deno.Reader,
  writer: Deno.Writer,
) {
  const encoder = new TextEncoder();
  for await (const line of readLines(reader)) {
    await writeAll(writer, encoder.encode(`[${prefix}] ${line}\n`));
  }
}

const cat = Deno.run({
  cmd: ["docker", "build", "--no-cache", ".", "-t", "foobar:latest"],
  cwd: "/path/to/your/project",
  stdout: "piped",
  stderr: "piped",
});

pipeThrough("docker", cat.stdout, Deno.stdout);
pipeThrough("docker", cat.stderr, Deno.stderr);
await cat.status();
console.log("Done!");