一尘不染

node.js shell命令执行

javascript

我仍在尝试掌握如何运行linux或Windows shell命令并在node.js中捕获输出的细节。最终,我想做这样的事情…

//pseudocode
output = run_command(cmd, args)

重要的一点是output必须对全局范围的变量(或对象)可用。我尝试了以下功能,但是由于某种原因,我被undefined打印到控制台了。

function run_cmd(cmd, args, cb) {
  var spawn = require('child_process').spawn
  var child = spawn(cmd, args);
  var me = this;
  child.stdout.on('data', function(me, data) {
    cb(me, data);
  });
}
foo = new run_cmd('dir', ['/B'], function (me, data){me.stdout=data;});
console.log(foo.stdout);  // yields "undefined" <------

我很难理解代码在哪里突破了…该模型的非常简单的原型可以工作…

function try_this(cmd, cb) {
  var me = this;
  cb(me, cmd)
}
bar = new try_this('guacamole', function (me, cmd){me.output=cmd;})
console.log(bar.output); // yields "guacamole" <----

有人可以帮助我了解为什么try_this()有效,但是run_cmd()无效吗?FWIW,我需要使用child_process.spawn,因为child_process.exec缓冲区限制为200KB。

最终决议

我接受詹姆斯·怀特(James White)的回答,但这是对我有用的确切代码…

function cmd_exec(cmd, args, cb_stdout, cb_end) {
  var spawn = require('child_process').spawn,
    child = spawn(cmd, args),
    me = this;
  me.exit = 0;  // Send a cb to set 1 when cmd exits
  me.stdout = "";
  child.stdout.on('data', function (data) { cb_stdout(me, data) });
  child.stdout.on('end', function () { cb_end(me) });
}
foo = new cmd_exec('netstat', ['-rn'], 
  function (me, data) {me.stdout += data.toString();},
  function (me) {me.exit = 1;}
);
function log_console() {
  console.log(foo.stdout);
}
setTimeout(
  // wait 0.25 seconds and print the output
  log_console,
250);

阅读 464

收藏
2020-05-01

共1个答案

一尘不染

这里需要解决三个问题:

首先
,您期望异步使用stdout时出现同步行为。run_cmd函数中的所有调用都是异步的,因此它将从子进程中产生并立即返回,而不管是否已从stdout读取部分,全部或没有数据。因此,当您跑步时

console.log(foo.stdout);

您会得到当前存储在foo.stdout中的所有信息,并且无法保证会发生什么,因为您的子进程可能仍在运行。

其次
是stdout是可读流,因此1)可以多次调用数据事件,并且2)回调被赋予一个缓冲区,而不是字符串。易于补救;只是改变

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, data){me.stdout=data;}
);

进入

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, buffer){me.stdout+=buffer.toString();}
);

这样我们就可以将缓冲区转换为字符串并将该字符串附加到我们的stdout变量中。

第三点 是,您只有在收到’end’事件时才能知道已收到所有输出,这意味着我们需要另一个侦听器和回调:

function run_cmd(cmd, args, cb, end) {
    // ...
    child.stdout.on('end', end);
}

因此,您的最终结果是:

function run_cmd(cmd, args, cb, end) {
    var spawn = require('child_process').spawn,
        child = spawn(cmd, args),
        me = this;
    child.stdout.on('data', function (buffer) { cb(me, buffer) });
    child.stdout.on('end', end);
}

// Run C:\Windows\System32\netstat.exe -an
var foo = new run_cmd(
    'netstat.exe', ['-an'],
    function (me, buffer) { me.stdout += buffer.toString() },
    function () { console.log(foo.stdout) }
);
2020-05-01