node.js shell 命令执行

IT技术 javascript node.js shell
2021-01-30 23:03:22

我仍在努力掌握如何在 node.js 中运行 linux 或 windows shell 命令并捕获输出的更精细的要点;最终,我想做这样的事情......

//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);
6个回答

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

首先是您在异步使用 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) }
);
这是一个很好的答案,对一些非常重要的 JS 概念进行了很好的解释。好的!
2021-03-24 23:03:22
你会想要this.stdout = "";run()函数内部,否则你console.log(foo.sdtout);会以undefined.
2021-03-24 23:03:22
“无法保证那会是什么,因为您的子进程可能仍在运行”关闭......但可以保证它不会在那个时间点设置,并且只会在最终调用回调时设置,正如你在别处指出的
2021-04-02 23:03:22

已接受答案的简化版本(第三点),对我有用。

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) });
child.stdout.on('close', (errCode) => { console.log(errCode) } )
2021-03-17 23:03:22
返回值怎么样,当进程返回一个非零时,我怎样才能得到它?
2021-03-27 23:03:22

我更简洁地使用了这个:

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

它完美地工作。:)

这很有效,并且不需要任何额外的节点module。我喜欢!
2021-03-17 23:03:22
sys.puts()已于 2011 年弃用(使用 Node.js v0.2.3)。你应该console.log()改用。
2021-03-22 23:03:22
哇!!这个答案是完美而优雅的。谢谢。
2021-04-05 23:03:22
这实际上有效......所以我想知道,为什么这不是答案?太简单了
2021-04-12 23:03:22

最简单的方法是只使用 ShellJS lib ...

$ npm install [-g] shelljs

执行示例:

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 函数的常见 shell 命令,包括:

  • 光盘
  • 修改
  • cp
  • 目录
  • 回声
  • 执行
  • 出口
  • 寻找
  • 格雷普
  • 输入
  • ls
  • 目录
  • MV
  • 弹出
  • 密码
  • R M
  • sed
  • 测试
  • 哪个
如何向 shell.exec("foo.sh") 调用的 shell 脚本添加参数?
2021-03-21 23:03:22
您可以将参数附加到字符串的顶部:shell.exec("foo.sh arg1 arg2 ... ")您的foo.sh脚本可以使用$1, $2... 等来引用这些
2021-04-01 23:03:22
如果您尝试执行的命令需要来自用户的输入,则不要使用 ShellJS exec()。这个函数本质上不是交互式的,因为它只会接受命令和打印输出,不能接受两者之间的输入。使用内置的 child_process 代替。例如https://stackoverflow.com/a/31104898/9749509
2021-04-01 23:03:22

我有一个类似的问题,我最终为此编写了一个节点扩展。您可以查看 git 存储库。它是开源的、免费的,还有所有的好东西!

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

ExecXI是一个用C++编写的节点扩展,用于逐条执行shell命令,将命令的输出实时输出到控制台。存在可选的链式和非链式方式;这意味着您可以选择在命令失败后停止脚本(链接),或者您可以继续,好像什么也没发生!

使用说明在自述文件中随意提出请求请求或提交问题!

我认为值得一提。