Node.js的外壳命令的执行(node.js shell command execution)

2019-07-18 13:21发布

我仍然在努力把握我怎么可以运行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的缓冲区限制。

最终解决

我接受詹姆斯 - 怀特的回答,但是这是为我工作的具体代码...

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

Answer 1:

这里有三个问题需要加以修正:

首先是你期望在使用标准输出异步同步行为。 一切都在你的呼叫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();}
);

让我们把我们的缓冲区为一个字符串,字符串追加到标准输出我们的变量。

是,你只能知道你已经收到所有输出,当你得到了“结束”事件,这意味着我们需要另一个监听器和回调:

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


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


Answer 3:

我用这个更简洁:

var sys = require('sys')
var exec = require('child_process').exec;
function puts(error, stdout, stderr) { sys.puts(stdout) }
exec("ls -la", puts);

它完美的作品。 :)



Answer 4:

简单的方法是只使用ShellJS LIB ...

$ npm install [-g] shelljs

EXEC实施例:

require('shelljs/global');

// Sync call to exec()
var version = exec('node --version', {silent:true}).output;

// Async call to exec()
exec('netstat.exe -an', function(status, output) {
  console.log('Exit status:', status);
  console.log('Program output:', output);
});

ShellJs.org支持映射为的NodeJS功能,包括许多常见的外壳命令:

  • 光盘
  • CHMOD
  • CP
  • 迪尔斯
  • 回声
  • EXEC
  • 出口
  • grep的
  • LN
  • LS
  • MKDIR
  • MV
  • POPD
  • PUSHD
  • PWD
  • R M
  • SED
  • 测试
  • 哪一个


Answer 5:

我有一个类似的问题,我结束了写这个节点扩展。 您可以检查出的git仓库。 它是开源和免费的,所有的好东西!

https://github.com/aponxi/npm-execxi

ExecXI是一个节点的扩展用C ++编写由一个执行shell命令之一,输出该命令输出到控制台实时。 可选的链接,以及奔放的方式存在; 这意味着你可以选择一个命令失败后(链接)停止脚本,或者您也可以继续运行,就像什么都没有发生!

用法说明在自述文件 。 随意让拉请求或提交的问题!

我认为这是值得一提的。



Answer 6:

@ TonyO'Hagan是comprehrensive shelljs的答案,但是,我想强调他的回答的同步版本:

var shell = require('shelljs');
var output = shell.exec('netstat -rn', {silent:true}).output;
console.log(output);


Answer 7:

同步的一行:

require('child_process').execSync("echo 'hi'", function puts(error, stdout, stderr) { console.log(stdout) });



Answer 8:

有一个在你的变量冲突run_cmd功能:

  var me = this;
  child.stdout.on('data', function(me, data) {
    // me is overriden by function argument
    cb(me, data);
  });

只需将它改成这样:

  var me = this;
  child.stdout.on('data', function(data) {
    // One argument only!
    cb(me, data);
  });

为了看到错误总是补充一点:

  child.stderr.on('data', function(data) {
      console.log( data );
  });

因为你正在尝试运行编辑你的代码失败dir 作为一个单独的独立程序提供。 它是在一个命令cmd过程。 如果你想用文件系统使用本地播放require( 'fs' )

或者(我不推荐),可以创建一个批处理文件,然后可以运行。 注意经由OS默认火灾批处理文件cmd



Answer 9:

你不是真的返回从RUN_CMD函数的任何信息。

function run_cmd(cmd, args, done) {
    var spawn = require("child_process").spawn;
    var child = spawn(cmd, args);
    var result = { stdout: "" };
    child.stdout.on("data", function (data) {
            result.stdout += data;
    });
    child.stdout.on("end", function () {
            done();
    });
    return result;
}

> foo = run_cmd("ls", ["-al"], function () { console.log("done!"); });
{ stdout: '' }
done!
> foo.stdout
'total 28520...'

工作得很好。 :)



Answer 10:

A promisified version of the most-awarded answer:

  runCmd: (cmd, args) => {
    return new Promise((resolve, reject) => {
      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 () { resolve(resp) })
    })
  }

To use:

 runCmd('ls').then(ret => console.log(ret))


文章来源: node.js shell command execution