节点.js shell 命令执行

2022-08-30 05:20:59

我仍然试图掌握如何运行linux或windows shell命令并在node.js捕获输出的更精细之处;最终,我想做这样的事情...

//pseudocode
output = run_command(cmd, args)

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

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" <----

有人能帮我理解为什么有效,为什么不起作用吗?FWIW,我需要使用child_process.spawn,因为child_process.exec有200KB的缓冲区限制。try_this()run_cmd()

最终解决方案

我接受詹姆斯·怀特的答案,但这是对我有用的确切代码......

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

答案 1

这里有三个问题需要解决:

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

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

答案 2

一个简化版本的接受的答案(第三点),对我来说只是工作。

function run_cmd(cmd, args, callBack ) {
    var spawn = require('child_process').spawn;
    var child = spawn(cmd, args);
    var resp = "";

    child.stdout.on('data', function (buffer) { resp += buffer.toString() });
    child.stdout.on('end', function() { callBack (resp) });
} // ()

用法:

run_cmd( "ls", ["-l"], function(text) { console.log (text) });

run_cmd( "hostname", [], function(text) { console.log (text) });