如何在Node.js中通过管道传输和保存spawnSync进程的输出?

isq*_*qua 5 javascript node.js

我同步生成一些命令,并希望两件事:

  1. 将其标准输出通过管道发送到process.stdout。
  2. 将标准输出保存到变量中。

我写了这段代码:

var spawnSync = require('child_process').spawnSync;
var result = spawnSync('ls', [ '-l', '-a' ]);
var savedOutput = result.stdout;

console.log(String(savedOutput));
Run Code Online (Sandbox Code Playgroud)

因此,我将stdout存储在savedOutput变量中-可以,然后将其注销。但是我还没有将其发送到stdout。如果生成的过程很长,并且一个接一个地编写字符串,那么我会很长时间看到空白屏幕,最后我会看到整个过程的标准输出。

我添加了管道选项:

var spawnSync = require('child_process').spawnSync;
var result = spawnSync('ls', [ '-l', '-a' ], {
    stdio: [ 'ignore', 1, 2 ]
});
var savedOutput = result.stdout;

console.log(String(savedOutput));
Run Code Online (Sandbox Code Playgroud)

生成的进程的标准输出通过管道传递到标准输出-可以。但是result.stdout为空。

我尝试使用流:

var spawnSync = require('child_process').spawnSync;
var stream = require('stream');
var grabber = new stream.Writable();

grabber._write = function(chunk, enc, done) {
    console.log('Chunk:');
    console.log(String(chunk));
    done();
};

var result = spawnSync('ls', [ '-l', '-a' ], {
    stdio: [ 'ignore', grabber, 2 ]
});
Run Code Online (Sandbox Code Playgroud)

...但出现错误:

internal/child_process.js:795
  throw new TypeError('Incorrect value for stdio stream: ' +
  ^

TypeError: Incorrect value for stdio stream: Writable
Run Code Online (Sandbox Code Playgroud)

如果设置grabber.fd = 2,则不会出现错误,但是子stdout会通过管道传递到stdout而不是采集卡。

所以。如何将子标准输出保存到变量中并同时通过管道将其输出到标准输出?

小智 7

这能解决您的问题吗?

var spawnSync = require('child_process').spawnSync;
var result = spawnSync('ls', [ '-l', '-a' ], {
    cwd: process.cwd(),
    env: process.env,
    stdio: 'pipe',
    encoding: 'utf-8'
});
var savedOutput = result.stdout;

console.log(String(savedOutput));
Run Code Online (Sandbox Code Playgroud)

  • 不,因为标准输出没有通过管道传输。尝试删除您的 console.log 并查看:没有输出。 (2认同)

Met*_*ean 6

有几种可能的解决方案,都涉及spawnSync's options。

此代码的实时版本位于https://repl.it/repls/MundaneConcernedMetric

const spawnSync = require('child_process').spawnSync;

// WITH NO OPTIONS:
// stdout is here, but is encoded as 'buffer'
const result_noOptions = spawnSync('ls', [ '-l', '-a' ]); // won't print anything
console.log(result_noOptions.stdout); // will print <Buffer ...> on completion

// WITH { encoding: 'utf-8'} OPTIONS:
// stdout is also here, _but only printed on completion of spawnSync_
const result_encoded = spawnSync('ls', [ '-l', '-a' ], { encoding: 'utf-8' }); // won't print anything
console.log(result_encoded.stdout); // will print ls results only on completion

// WITH { stdio: 'inherit' } OPTIONS:
// there's no stdout, _because it prints immediately to your terminal_
const result_inherited = spawnSync('ls', [ '-l', '-a' ], { stdio: 'inherit'}); // will print as it's processing
console.log(result_inherited.stdout); // will print null
Run Code Online (Sandbox Code Playgroud)

除了stdout,您还可以获得:pid, output, stdout, stderr, status, signal, & error。

https://nodejs.org/api/child_process.html#child_process_child_process_spawnsync_command_args_options


小智 5

我认为问题在于“spawnSync”是同步的,并且在子进程退出之前不会将控制权返回给节点。这意味着节点在子节点执行期间不进行任何处理,因此无法看到子节点的任何中间输出。

您需要使用非“同步”生成。这将带来额外的复杂性,因为您的代码是异步的,您需要等待 'close' 事件以确保收集了子数据。你需要弄清楚如何处理 stderr。像这样的东西:

const spawn = require('child_process').spawn;
const lsChild = spawn('ls', [ '-l', '-a' ]);

let savedOutput = '';

lsChild.stdout.on('data', data => {
   const strData = data.toString();
   console.log(strData);
   savedOutput += strData;
});

lsChild.stderr.on('data', data => {
   assert(false, 'Not sure what you want with stderr');
});

lsChild.on('close', code => {
   console.log('Child exited with', code, 'and stdout has been saved');
   // at this point 'savedOutput' contains all your data.
});
Run Code Online (Sandbox Code Playgroud)