Js shell 命令执行

我仍然试图掌握如何运行 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);
160690 次浏览

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

或者(我不建议这样做) ,您可以创建一个批处理文件,然后可以运行它。注意,默认情况下操作系统通过 cmd触发批处理文件。

There are three issues here that need to be fixed:

第一个 是您希望在异步使用 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();}
);

因此,我们将缓冲区转换为字符串,并将该字符串附加到标准输出变量。

Third is that you can only know you've received all output when you get the 'end' event, which means we need another listener and callback:

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

您实际上并没有从 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...'

效果很好

I had a similar problem and I ended up writing a node extension for this. You can check out the git repository. It's open source and free and all that good stuff !

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

ExecXI 是用 C + + 编写的节点扩展,用于执行 shell 命令 中将命令的输出输出到控制台 可选的链接和不链接的方式是存在的; 意义 that you can choose to stop the script after a command fails 或者你可以继续假装什么都没发生!

使用说明在 ReadMe 文件。请随意拉请求或提交问题!

我觉得值得一提。

A simplified version of the accepted answer (third point), just worked for me.

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

我用得更简洁:

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

效果非常好:)

Simplest way is to just use the 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);
});

Org 支持映射为 NodeJS 函数的许多常见 shell 命令,包括:

  • CD
  • Chmod
  • CP
  • 紧急情况
  • Echo
  • 执行官
  • 出口
  • 找到
  • Grep
  • 进去
  • ls
  • Mkdir
  • MV
  • Pod
  • pwd
  • Rm
  • Sed
  • 测试
  • 哪个

@ TonyO‘ Hagan 是 shelljs的综合答案,但是,我想强调一下他的答案的同步版本:

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

Synchronous one-liner:

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

最佳答案的承诺版本:

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