node.js shell命令执行

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

//pseudocode output = run_command(cmd, args) 

重要的是output必须可用于全局范围的variables(或对象)。 我尝试了以下function,但由于某种原因,我得到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的缓冲区限制。

BOUNTY奖

我到目前为止没有成功的第一个答案

 // run my shell command 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(data) { cb(me, data); }); } // Run C:\Windows\System32\netstat.exe -an foo = new run_cmd('netstat.exe', ['-an'], function (me, data){me.stdout=data;}); app.listen(3000); console.log('Express app started on port 3000'); console.log(foo.stdout); // <----- Still yields 'undefined' 

奖金将奖励给可以纠正我现有代码错误的人,以便我可以调用foo = new run_cmd('netstat.exe', ['-an'], function (me, data){me.stdout=data;}); 并接收foo.stdout的输出(在全局variables作用域中)。

最终决议

我接受詹姆斯怀特的答案,但这是确切的代码,为我工作…

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

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

首先 ,您在asynchronous使用stdout时期待同步行为。 run_cmd函数中的所有调用都是asynchronous的,所以它将产生subprocess,并立即返回,无论是否有一部分或全部数据已经从stdout中读取。 就这样,当你跑步

 console.log(foo.stdout); 

你会得到什么现在存储在foo.stdout,并不能保证这将是因为你的subprocess可能仍然在运行。

其次 ,stdout是一个可读的stream ,因此1)数据事件可以被多次调用,2)callback被赋予一个缓冲区,而不是一个string。 易于补救; 只是改变

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

所以我们将我们的缓冲区转换成一个string,并将该string追加到我们的stdoutvariables。

第三 ,你只能知道你已经收到所有输出,当你得到'结束'事件,这意味着我们需要另一个监听器和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) } ); 

接受答案(第三点)的简化版本,只为我工作。

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

最简单的方法是使用ShellJS库…

 $ 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支持许多映射为NodeJSfunction的常见shell命令,包括:

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

我更简洁地使用了这个:

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

它完美的作品。 🙂

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

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

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

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

我认为这是值得一提的。

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

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

同步单线:

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

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

另外(我不build议),你可以创build一个batch file,然后你可以运行。 请注意,OS默认通过cmd激活batch file。

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

工作得很好。 🙂