简体   繁体   English

node.js shell 命令执行

[英]node.js shell command execution

I am still trying to grasp the finer points of how I can run a linux or windows shell command and capture output within node.js;我仍在努力掌握如何运行 linux 或 windows shell 命令并在 node.js 中捕获输出的更精细的要点; ultimately, I want to do something like this...最终,我想做这样的事情......

//pseudocode
output = run_command(cmd, args)

The important piece is that output must be available to a globally scoped variable (or object).重要的是output必须对全局范围的变量(或对象)可用。 I tried the following function, but for some reason, I get undefined printed to the console...我尝试了以下功能,但由于某种原因,我将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" <------

I'm having trouble understanding where the code breaks above... a very simple prototype of that model works...我无法理解上面的代码在哪里中断......该模型的一个非常简单的原型工作......

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

Can someone help me understand why try_this() works, and run_cmd() does not?有人可以帮助我理解为什么try_this()有效,而run_cmd()无效吗? FWIW, I need to use child_process.spawn , because child_process.exec has a 200KB buffer limit. FWIW,我需要使用child_process.spawn ,因为child_process.exec有 200KB 缓冲区限制。

Final Resolution最终决议

I'm accepting James White's answer, but this is the exact code that worked for me...我接受詹姆斯怀特的回答,但这是对我有用的确切代码......

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

There are three issues here that need to be fixed:这里有三个问题需要解决:

First is that you are expecting synchronous behavior while using stdout asynchronously.首先是您在异步使用 stdout 时期望同步行为。 All of the calls in your run_cmd function are asynchronous, so it will spawn the child process and return immediately regardless of whether some, all, or none of the data has been read off of stdout. run_cmd函数中的所有调用都是异步的,因此它会生成子进程并立即返回,无论是否从 stdout 中读取了部分、全部或全部数据。 As such, when you run因此,当您运行

console.log(foo.stdout);

you get whatever happens to be stored in foo.stdout at the moment, and there's no guarantee what that will be because your child process might still be running.你现在得到存储在 foo.stdout 中的任何东西,并且不能保证那会是什么,因为你的子进程可能仍在运行。

Second is that stdout is a readable stream , so 1) the data event can be called multiple times, and 2) the callback is given a buffer, not a string.其次是 stdout 是一个可读流,所以 1) 数据事件可以被多次调用,2) 回调被赋予一个缓冲区,而不是一个字符串。 Easy to remedy;易于补救; just change只是改变

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, data){me.stdout=data;}
);

into进入

foo = new run_cmd(
    'netstat.exe', ['-an'], function (me, buffer){me.stdout+=buffer.toString();}
);

so that we convert our buffer into a string and append that string to our stdout variable.以便我们将缓冲区转换为字符串并将该字符串附加到我们的 stdout 变量中。

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:第三,只有在收到 'end' 事件时,您才能知道已收到所有输出,这意味着我们需要另一个侦听器和回调:

function run_cmd(cmd, args, cb, end) {
    // ...
    child.stdout.on('end', end);
}

So, your final result is this:所以,你的最终结果是这样的:

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

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

Usage:用法:

run_cmd( "ls", ["-l"], function(text) { console.log (text) });

run_cmd( "hostname", [], function(text) { console.log (text) });

I used this more concisely :我更简洁地使用了这个:

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

it works perfectly.它完美地工作。 :) :)

Simplest way is to just use the ShellJS lib ...最简单的方法是只使用 ShellJS lib ...

$ npm install [-g] shelljs

EXEC Example:执行示例:

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 supports many common shell commands mapped as NodeJS functions including: ShellJs.org支持许多映射为 NodeJS 函数的常见 shell 命令,包括:

  • cat
  • cd光盘
  • chmod修改
  • cp cp
  • dirs目录
  • echo回声
  • exec执行
  • exit出口
  • find寻找
  • grep格雷普
  • ln输入
  • ls ls
  • mkdir目录
  • mv MV
  • popd弹出
  • pushd
  • pwd密码
  • rm R M
  • sed sed
  • test测试
  • which哪个

I had a similar problem and I ended up writing a node extension for this.我有一个类似的问题,我最终为此编写了一个节点扩展。 You can check out the git repository.您可以查看 git 存储库。 It's open source and free and all that good stuff !它是开源的,免费的,还有所有的好东西!

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

ExecXI is a node extension written in C++ to execute shell commands one by one, outputting the command's output to the console in real-time. ExecXI是一个用C++编写的节点扩展,用于逐条执行shell命令,将命令的输出实时输出到控制台。 Optional chained, and unchained ways are present;存在可选的链式和非链式方式; meaning that you can choose to stop the script after a command fails (chained), or you can continue as if nothing has happened !这意味着您可以选择在命令失败(链接)后停止脚本,或者您可以继续,好像什么也没发生!

Usage instructions are in the ReadMe file .使用说明在自述文件中 Feel free to make pull requests or submit issues!随意提出请求请求或提交问题!

I thought it was worth to mention it.我认为值得一提。

@TonyO'Hagan is comprehrensive shelljs answer, but, I would like to highlight the synchronous version of his answer: @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) 
});

There's a variable conflict in your run_cmd function:您的run_cmd函数中存在变量冲突:

  var me = this;
  child.stdout.on('data', function(me, data) {
    // me is overriden by function argument
    cb(me, data);
  });

Simply change it to this:只需将其更改为:

  var me = this;
  child.stdout.on('data', function(data) {
    // One argument only!
    cb(me, data);
  });

In order to see errors always add this:为了看到错误总是添加这个:

  child.stderr.on('data', function(data) {
      console.log( data );
  });

EDIT You're code fails because you are trying to run dir which is not provided as a separate standalone program.编辑您的代码失败,因为您正在尝试运行作为单独的独立程序提供的dir It is a command in cmd process.它是cmd进程中的一个命令。 If you want to play with filesystem use native require( 'fs' ) .如果您想使用文件系统,请使用本机require( 'fs' )

Alternatively ( which I do not recommend ) you can create a batch file which you can then run.或者(我不推荐)您可以创建一个批处理文件,然后您可以运行该文件。 Note that OS by default fires batch files via cmd .请注意,操作系统默认通过cmd触发批处理文件。

You're not actually returning anything from your run_cmd function.您实际上并未从 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...'

Works just fine.工作得很好。 :) :)

A promisified version of the most-awarded answer:获奖最多的答案的承诺版本:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM