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

时间:2016-03-17 17:29:44

标签: javascript node.js

我同步生成一些命令并想要两件事:

  1. 将其标准输出管道传递给process.stdout。
  2. 将标准输出保存到变量中。
  3. 我写了这段代码:

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

    所以,我将stdout存储在savedOutput变量中 - 没关系,然后将其记录下来。但是我还没把它管到stdout。如果生成的进程很长并逐个写字符串,我会看到空屏很长时间,最后我看到整个进程的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));
    

    生成过程的标准输出通过管道输送到标准输出 - 没关系。但是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 ]
    });
    

    ...但收到错误:

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

    如果我设置grabber.fd = 2,我不会收到错误,但是子标准输出管道输入stdout而不是抓取器。

    因此。如何将子stdout保存到变量中并同时将其传递给stdout?

4 个答案:

答案 0 :(得分:2)

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

您需要使用非“同步”生成。这将带来更多的复杂性,因为您的代码是异步的,并且您需要等待“关闭”事件以确保收集了子数据。您需要弄清楚如何使用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.
});

答案 1 :(得分:2)

有两种可能的解决方案,都涉及spawnSync的{​​{1}}。

https://repl.it/repls/MundaneConcernedMetric

有此代码的实时版本。
options

除了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 ,您还可以获得:stdoutpidoutputstdoutstderr,{{1 }}和status

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

答案 2 :(得分:0)

这会解决您的问题吗?

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

答案 3 :(得分:-2)

stdout没有帮助获取spawnSync的输出,因此使用它来代替在变量中存储output。我正在使用Windows cmd

var cp = require('child_process');

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

    var output = result.output.toString();