javascript - node.js shell命令执行

我仍然试图掌握如何运行linux或windows shell命令以及在node.js中捕获输出的更好点; 最终,我想做这样的事......

//pseudocode

output = run_command(cmd, args)

重要的是child_process.exec必须可用于全局范围的变量(或对象)。 我尝试了以下功能,但出于某种原因,我将run_cmd()打印到控制台...

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"

有人可以帮我理解为什么child_process.exec有效,而run_cmd()不行吗? FWIW,我需要使用child_process.exec,因为child_process.exec具有200KB的缓冲区限制。

最终决议

我接受了James White的回答,但这是对我有用的确切代码......

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

10个解决方案

88 votes

这里有三个问题需要修复:

首先,您在异步使用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变量中。

第三,当你收到'结束'事件时,你只能知道你已收到所有输出,这意味着我们需要另一个监听器和回调:

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

);

James White answered 2019-07-12T15:45:46Z

76 votes

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

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

cibercitizen1 answered 2019-07-12T15:46:14Z

45 votes

我更简洁地使用了这个:

var sys = require('sys')

var exec = require('child_process').exec;

function puts(error, stdout, stderr) { sys.puts(stdout) }

exec("ls -la", puts);

它完美地运作。:)

Mimouni answered 2019-07-12T15:46:50Z

42 votes

最简单的方法就是使用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函数的常见shell命令,包括:

光盘

CHMOD

CP

迪尔斯

回声

EXEC

出口

grep的

LN

LS

MKDIR

MV

POPD

PUSHD

PWD

R M

SED

测试

哪一个

Tony O'Hagan answered 2019-07-12T15:49:44Z

4 votes

我遇到了类似的问题,最后我为此编写了一个节点扩展。 你可以看看git存储库。 它是开源的,免费的,所有这些好东西!

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

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

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

我认为值得一提。

Logan answered 2019-07-12T15:50:28Z

3 votes

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

var shell = require('shelljs');

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

console.log(output);

Stephen Quan answered 2019-07-12T15:50:54Z

1 votes

同步单线程:

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

Victorio Berra answered 2019-07-12T15:51:28Z

0 votes

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

});

编辑您的代码失败,因为您尝试运行cmd,这不是作为单独的独立程序提供的。 它是cmd进程中的命令。 如果你想使用文件系统使用原生require( 'fs' )。

或者(我不建议)您可以创建一个批处理文件然后运行。 请注意,默认情况下,OS会通过cmd触发批处理文件。

freakish answered 2019-07-12T15:52:27Z

0 votes

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

工作得很好。:)

Chris Eineke answered 2019-07-12T15:53:04Z

0 votes

获奖最多的答案:

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

})

}

使用:

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

Frank answered 2019-07-12T15:53:33Z