简体   繁体   English

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

[英]How to pipe and save output of spawnSync process in Node.js?

I spawn some command synchronously and want two things:我同步生成一些命令并想要两件事:

  1. Pipe its stdout to process.stdout.将其标准输出通过管道传输到 process.stdout。
  2. Save the stdout into variable.将标准输出保存到变量中。

I've written this code:我写了这段代码:

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

console.log(String(savedOutput));

So, I store stdout in savedOutput variable — it's ok, and log it out.所以,我将 stdout 存储在 savedOutput 变量中——没关系,然后将其注销。 But I haven't pipe it to stdout.但我还没有将它传送到标准输出。 If the spawned process is long and write strings one by one, I see empty screen a long time, and at the end I see whole stdout of process.如果生成的进程很长并且一个一个地写字符串,我会看到很长时间的空白屏幕,最后我会看到整个进程的标准输出。

I've add options for piping:我添加了管道选项:

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

console.log(String(savedOutput));

Stdout of spawned process is piped to stdout — it's ok.生成的进程的标准输出通过管道传输到标准输出 — 没问题。 But result.stdout is empty.但是 result.stdout 是空的。

I've tried to use stream:我试过使用流:

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 ]
});

... but get an error: ...但得到一个错误:

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

TypeError: Incorrect value for stdio stream: Writable

If I set grabber.fd = 2 , I don't get an error, but child stdout pipes to stdout instead of grabber.如果我设置grabber.fd = 2 ,我不会收到错误,但是子标准输出管道到标准输出而不是抓取器。

So.所以。 How to save child stdout into variable and pipe it to stdout in the same time?如何将子标准输出保存到变量中并同时将其通过管道传输到标准输出?

Does this solve your problem?这能解决您的问题吗?

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));

There are a couple of possible solutions, both involving spawnSync 's options .有几种可能的解决方案,都涉及spawnSyncoptions

There is a live version of this code available at https://repl.it/repls/MundaneConcernedMetric此代码的实时版本位于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

In addition to stdout , you can also get: pid , output , stdout , stderr , status , signal , & error .除了stdout ,您还可以获得: pidoutputstdoutstderrstatussignalerror

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

I think the problem is that "spawnSync" is synchronous, and does not return control to node until the child process has exited.我认为问题在于“spawnSync”是同步的,并且在子进程退出之前不会将控制权返回给节点。 This means node does no processing during the execution of the child, and thus cannot see any of the intermediate output from the child.这意味着节点在子节点执行期间不进行任何处理,因此无法看到子节点的任何中间输出。

You need to use the non-"sync" spawn.您需要使用非“同步”生成。 This will have additional complications in that your code is async, and you need to wait for the 'close' event to be sure the child data is collected.这将带来额外的复杂性,因为您的代码是异步的,您需要等待 'close' 事件以确保收集了子数据。 And you need to figure out what to do with stderr.你需要弄清楚如何处理 stderr。 Something like this:像这样的东西:

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.
});

stdout was not helping to get output for spawnSync, so used this instead for storing output in a variable. stdout没有帮助获取 spawnSync 的输出,因此使用它代替将output存储在变量中。 I'm using Windows cmd我正在使用 Windows cmd

var cp = require('child_process');

var ls = cp.spawnSync('cmd.exe', ['/c', 'my.bat']);

    var output = result.output.toString();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM