内容简介:翻译:疯狂的技术宅原文:本文首发微信公众号:jingchengyideng
翻译:疯狂的技术宅
原文: http://2ality.com/2018/05/chi...
本文首发微信公众号:jingchengyideng
欢迎关注,每天都给你推送新鲜的前端技术文章
在本中,我们在 Node.js 中把 shell 命令作为子进程运行。然后异步读取这些进程的 stdout 并写入其 stdin。
在子进程中运行 shell 命令
首先从在子进程中运行 shell 命令开始:
const {onExit} = require('@rauschma/stringio'); const {spawn} = require('child_process'); async function main() { const filePath = process.argv[2]; console.log('INPUT: '+filePath); const childProcess = spawn('cat', [filePath], {stdio: [process.stdin, process.stdout, process.stderr]}); // (A) await onExit(childProcess); // (B) console.log('### DONE'); } main();
解释:
-
我们用了
spawn()
,它可以使我们在命令运行时访问命令的 stdin,stdout 和 stderr。- 在 A 行中,我们将子进程的 stdin 连接到当前进程的 stdin。
- B 行等待该过程完成。
等待子进程通过 Promise 退出
函数 onExit()
如下所示。
function onExit(childProcess: ChildProcess): Promise<void> { return new Promise((resolve, reject) => { childProcess.once('exit', (code: number, signal: string) => { if (code === 0) { resolve(undefined); } else { reject(new Error('Exit with error code: '+code)); } }); childProcess.once('error', (err: Error) => { reject(err); }); }); }
子进程的实现
以下代码用 @rauschma/stringio
异步写入以 shell 命令运行的子进程的 stdin
:
const {streamWrite, streamEnd, onExit} = require('@rauschma/stringio'); const {spawn} = require('child_process'); async function main() { const sink = spawn('cat', [], {stdio: ['pipe', process.stdout, process.stderr]}); // (A) writeToWritable(sink.stdin); // (B) await onExit(sink); console.log('### DONE'); } main(); async function writeToWritable(writable) { await streamWrite(writable, 'First line\n'); await streamWrite(writable, 'Second line\n'); await streamEnd(writable); }
我们为 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 写流的操作通常涉及回调( 参见文档 )。代码如下。
function streamWrite( stream: Writable, chunk: string|Buffer|Uint8Array, encoding='utf8'): Promise<void> { return new Promise((resolve, reject) => { const errListener = (err: Error) => { stream.removeListener('error', errListener); reject(err); }; stream.addListener('error', errListener); const callback = () => { stream.removeListener('error', errListener); resolve(undefined); }; stream.write(chunk, encoding, callback); }); }
streamEnd()
的工作方式是类似的。
从子进程中读取数据
下面的代码使用异步迭代(C行)来读取子进程的 stdout
中的内容:
const {chunksToLinesAsync, chomp} = require('@rauschma/stringio'); const {spawn} = require('child_process'); async function main() { const filePath = process.argv[2]; console.log('INPUT: '+filePath); const source = spawn('cat', [filePath], {stdio: ['ignore', 'pipe', process.stderr]}); // (A) await echoReadable(source.stdout); // (B) console.log('### DONE'); } main(); async function echoReadable(readable) { for await (const line of chunksToLinesAsync(readable)) { // (C) console.log('LINE: '+chomp(line)) } }
解释:
- A行:我们忽略 stdin,希望通过流访问 stdout 并将 stderr 转发到
process.stderr
。 - B行:开始
awat
直到echoReadable()
完成。没有这个await
,DONE
将会在调用source.stdout
之前被输出。
在子进程之间进行管道连接
在下面的例子中,函数 transform()
将会:
-
从
source
子进程的stdout
中读取内容。- 将内容写入
sink
子进程的stdin
。
- 将内容写入
换句话说,我们正在实现类似 Unix 管道的功能:
cat someFile.txt | transform() | cat
这是代码:
const {chunksToLinesAsync, streamWrite, streamEnd, onExit} = require('@rauschma/stringio'); const {spawn} = require('child_process'); async function main() { const filePath = process.argv[2]; console.log('INPUT: '+filePath); const source = spawn('cat', [filePath], {stdio: ['ignore', 'pipe', process.stderr]}); const sink = spawn('cat', [], {stdio: ['pipe', process.stdout, process.stderr]}); transform(source.stdout, sink.stdin); await onExit(sink); console.log('### DONE'); } main(); async function transform(readable, writable) { for await (const line of chunksToLinesAsync(readable)) { await streamWrite(writable, '@ '+line); } await streamEnd(writable); }
扩展阅读
- 博客:“ 通过 Node.js 的异步迭代读取流 ”
- “探索ES2018和ES2019”中的“ 异步迭代 一章
- “探索ES2016和ES2017”中的“ 异步功能 ” 一章
本文首发微信公众号:jingchengyideng
欢迎扫描二维码关注公众号,每天都给你推送新鲜的前端技术文章
以上所述就是小编给大家介绍的《在 Node.js 中用子进程操作标准输入/输出》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- R中用线性回归进行预测建模
- 在Markdown中用mermaid语法绘制图表
- iOS面试题·项目中用过 Runtime 吗?
- 在docker中用Tomcat运行web项目
- 在项目实践中用更优雅的方式处理数组问题
- ajax中用josnp接收josn数据的实现方法
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Linux内核设计与实现
拉芙 / 陈莉君、唐华、张波 / 机械工业出版社 / 2006-1 / 38.00元
《Linux内核设计与实现》基于Linux2.6内核系列详细介绍Linux内核系统,覆盖了从核心内核系统的应用到内核设计与实现等各方面的内容。主要内容包括:进程管理、系统调用、中断和中断处理程序、内核同步、时间管理、内存管理、地址空间、调试技术等。本书理论联系实践,既介绍理论也讨论具体应用,能够带领读者快速走进Linux内核世界,真正开发内核代码。 本书适合作为高等院校操作系统课程的教材......一起来看看 《Linux内核设计与实现》 这本书的介绍吧!