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...'
工作得很好。 🙂