美文网首页前端学习
在 Node.js 中通过子进程操作标准输入/输出

在 Node.js 中通过子进程操作标准输入/输出

作者: 1194b60087a9 | 来源:发表于2019-04-22 17:18 被阅读0次

在本中,我们在 Node.js 中把 shell 命令作为子进程运行。然后异步读取这些进程的 stdout 并写入其 stdin。

在子进程中运行 shell 命令

首先从在子进程中运行 shell 命令开始:

1const {onExit} = require('@rauschma/stringio');

2const {spawn} = require('child_process');

3

4async function main() {

5 const filePath = process.argv[2];

6 console.log('INPUT: '+filePath);

7

8 const childProcess = spawn('cat', [filePath],

9 {stdio: [process.stdin, process.stdout, process.stderr]}); // (A)

10

11 await onExit(childProcess); // (B)

12

13 console.log('### DONE');

14}

15main();

解释:

我们用了 spawn(),它可以使我们在命令运行时访问命令的 stdin,stdout 和 stderr。

在 A 行中,我们将子进程的 stdin 连接到当前进程的 stdin。

B 行等待该过程完成。

等待子进程通过 Promise 退出

函数 onExit()如下所示。

1function onExit(childProcess: ChildProcess): Promise {

2 return new Promise((resolve, reject) => {

3 childProcess.once('exit', (code: number, signal: string) => {

4 if (code === 0) {

5 resolve(undefined);

6 } else {

7 reject(new Error('Exit with error code: '+code));

8 }

9 });

10 childProcess.once('error', (err: Error) => {

11 reject(err);

12 });

13 });

14}

子进程的实现

以下代码用 @rauschma/stringio 异步写入以 shell 命令运行的子进程的 stdin:

1const {streamWrite, streamEnd, onExit} = require('@rauschma/stringio');

2const {spawn} = require('child_process');

3

4async function main() {

5 const sink = spawn('cat', [],

6 {stdio: ['pipe', process.stdout, process.stderr]}); // (A)

7

8 writeToWritable(sink.stdin); // (B)

9 await onExit(sink);

10

11 console.log('### DONE');

12}

13main();

14

15async function writeToWritable(writable) {

16 await streamWrite(writable, 'First line');

17 await streamWrite(writable, 'Second line');

18 await streamEnd(writable);

19}

我们为 shell 命令生成一个名为 sink 的独立进程。用 writeToWritable 写入 sink.stdin。它借助 await 异步执行并暂停,以避免缓冲区被消耗太多。

解释:

在A行中,我们告诉 spawn() 通过 sink.stdin('pipe')访问 stdin。 stdout 和 stderr 被转发到 process.stdin 和 process.stderr,如前面所述。

在B行中不会 await 写完成。而是 await 子进程 sink 完成。

接下来了解 streamWrite() 的工作原理。

写流操作的 promise

Node.js 写流的操作通常涉及回调(参见文档【https://nodejs.org/dist/latest-v10.x/docs/api/stream.html#stream_writable_write_chunk_encoding_callback】)。代码如下。

1function streamWrite(

2 stream: Writable,

3 chunk: string|Buffer|Uint8Array,

4 encoding='utf8'): Promise {

5 return new Promise((resolve, reject) => {

6 const errListener = (err: Error) => {

7 stream.removeListener('error', errListener);

8 reject(err);

9 };

10 stream.addListener('error', errListener);

11 const callback = () => {

12 stream.removeListener('error', errListener);

13 resolve(undefined);

14 };

15 stream.write(chunk, encoding, callback);

16 });

17}

streamEnd()的工作方式是类似的。

从子进程中读取数据

下面的代码使用异步迭代(C行)来读取子进程的 stdout 中的内容:

1const {chunksToLinesAsync, chomp} = require('@rauschma/stringio');

2const {spawn} = require('child_process');

3

4async function main() {

5 const filePath = process.argv[2];

6 console.log('INPUT: '+filePath);

7

8 const source = spawn('cat', [filePath],

9 {stdio: ['ignore', 'pipe', process.stderr]}); // (A)

10

11 await echoReadable(source.stdout); // (B)

12

13 console.log('### DONE');

14}

15main();

16

17async function echoReadable(readable) {

18 for await (const line of chunksToLinesAsync(readable)) { // (C)

19 console.log('LINE: '+chomp(line))

20 }

21}

解释:

A行:我们忽略 stdin,希望通过流访问 stdout 并将 stderr 转发到process.stderr。

B行:开始 awat 直到 echoReadable() 完成。没有这个 await,DONE 将会在调用 source.stdout 之前被输出。

在子进程之间进行管道连接

在下面的例子中,函数transform() 将会:

从 source 子进程的 stdout 中读取内容。

将内容写入 sink 子进程的 stdin。

换句话说,我们正在实现类似 Unix 管道的功能:

1cat someFile.txt | transform() | cat

这是代码:

1const {chunksToLinesAsync, streamWrite, streamEnd, onExit}

2  = require('@rauschma/stringio');

3const {spawn} = require('child_process');

4

5async functionmain(){

6  const filePath = process.argv[2];

7  console.log('INPUT: '+filePath);

8

9  const source = spawn('cat', [filePath],

10    {stdio: ['ignore', 'pipe', process.stderr]});

11  const sink = spawn('cat', [],

12    {stdio: ['pipe', process.stdout, process.stderr]});

13

14  transform(source.stdout, sink.stdin);

15  await onExit(sink);

16

17  console.log('### DONE');

18}

19main();

20

21async functiontransform(readable, writable){

22  for await (const line of chunksToLinesAsync(readable)) {

23    await streamWrite(writable, '@ '+line);

24  }

25  await streamEnd(writable);

26}

十五年编程经验,今年1月整理了一批2019年最新WEB前端教学视频,不论是零基础想要学习前端还是学完在工作想要提升自己,这些资料都会给你带来帮助,从HTML到各种框架,帮助所有想要学好前端的同学,学习规划、学习路线、学习资料、问题解答。只要加入WEB前端学习交流Q群:296212562,即可免费获取。

相关文章

  • 在 Node.js 中通过子进程操作标准输入/输出

    在本中,我们在 Node.js 中把 shell 命令作为子进程运行。然后异步读取这些进程的 stdout 并写入...

  • golang子进程的的标准输出和标准错误

    golang子进程的的标准输出和标准错误 使用exec.Run()运行子进程的时候,子进程的标准输入输出在哪里呢。...

  • APUE读书笔记-15进程内部通信(2)

    3、popen和pclose函数 一个常用的操作就是给一个进程创建管道,通过管道读取它的标准输出以及向它的标准输入...

  • pipe() 系统调用

    从概念上讲,管道(pipe)是两个进程之间的连接,它使得一个进程的标准输出成为另一个进程的标准输入。在UNIX操作...

  • 初学UNIX T3

    3.1 重定向 UNIX命令发起的大部分进程是输出在标准输出中的(也就是终端屏幕),输入也是来自 于标准输入(也就...

  • linux重定向输入输出总结

    标准输入输出 在 Linux 系统中:标准输入(stdin)默认为键盘输入;标准输出(stdout)默认为屏幕输出...

  • day13-重定向

    1.什么是重定向 2.为何要使用重定向 3.标准输入与输出 进程将从标准输入中得到数据,将正常输出打印至屏幕终端,...

  • linux中的文件描述符以及重定向

    在linux操作系统中,使用一个正整数来描述一个文件操作。 0 标准输入 1 标准输出 2 标准错误 注意 2>&...

  • 8月10日Node.js的readline模块

    什么是Readline Readline是Node.js里实现标准输入输出的封装好的模块,通过这个模块我们可以以逐...

  • Node之进程

    Node.js中的进程 在操作系统中,每个应用程序都是一个进程类的实例对象。在Node.js中,使用process...

网友评论

    本文标题:在 Node.js 中通过子进程操作标准输入/输出

    本文链接:https://www.haomeiwen.com/subject/qirugqtx.html