node.js同步执行系统命令

时间:2010-12-14 19:59:43

标签: javascript command node.js exec sync

我需要 node.js 功能

result = execSync('node -v');

同步执行给定的命令行并返回该命令文本的所有stdout。

  

PS。同步是错误的。我知道。仅供个人使用。

更新

现在我们有mgutz的解决方案,它给我们退出代码,但不是stdout!仍在等待更准确的答案。

更新

mgutz 更新了他的答案,解决方案就在这里:)
另外,如 dgo.a 所述,还有独立模块exec-sync

更新2014-07-30

ShellJS lib到了。考虑到这是目前最好的选择。


更新2015-02-10

最后一次! NodeJS 0.12本身支持execSync 见官方docs

12 个答案:

答案 0 :(得分:121)

Node.js(自版本0.12起 - 所以有一段时间)支持execSync

child_process.execSync(command[, options])

您现在可以直接执行此操作:

const execSync = require('child_process').execSync;
code = execSync('node -v');

它会做你期望的。 (默认为将i / o结果传递给父进程)。请注意,您现在也可以spawnSync

答案 1 :(得分:54)

请参阅execSync库。

使用node-ffi相当容易。我不建议使用服务器进程,但对于一般开发实用程序,它可以完成任务。安装库。

npm install node-ffi

示例脚本:

var FFI = require("node-ffi");
var libc = new FFI.Library(null, {
  "system": ["int32", ["string"]]
});

var run = libc.system;
run("echo $USER");

[编辑2012年6月:如何获得STDOUT]

var lib = ffi.Library(null, {
    // FILE* popen(char* cmd, char* mode);
    popen: ['pointer', ['string', 'string']],

    // void pclose(FILE* fp);
    pclose: ['void', [ 'pointer']],

    // char* fgets(char* buff, int buff, in)
    fgets: ['string', ['string', 'int','pointer']]
});

function execSync(cmd) {
  var
    buffer = new Buffer(1024),
    result = "",
    fp = lib.popen(cmd, 'r');

  if (!fp) throw new Error('execSync error: '+cmd);

  while(lib.fgets(buffer, 1024, fp)) {
    result += buffer.readCString();
  };
  lib.pclose(fp);

  return result;
}

console.log(execSync('echo $HOME'));

答案 2 :(得分:31)

使用ShellJS模块。

exec函数没有提供回调。

示例:

var version = exec('node -v').output;

答案 3 :(得分:23)

在node.js中有一个名为asyncblock的流量控制的优秀模块。如果在函数中包装代码对于您的情况是可以的,则可以考虑以下示例:

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

asyncblock(function (flow) {
    exec('node -v', flow.add());
    result = flow.wait();
    console.log(result);    // There'll be trailing \n in the output

    // Some other jobs
    console.log('More results like if it were sync...');
});

答案 4 :(得分:11)

这在Node.js中是不可能的,child_process.spawnchild_process.exec都是从头开始构建为异步的。

有关详细信息,请参阅:https://github.com/ry/node/blob/master/lib/child_process.js

如果你真的想要这个阻塞,那么把所有需要发生的事情放在回调中,或者建立你自己的队列来阻止处理这个,我想你可以使用Async.js来完成这个任务

或者,如果你有太多的时间花钱,那就自己在Node.js中进行攻击。

答案 5 :(得分:7)

只是添加即使您使用它们的用例很少,spawnSync / execFileSync / execSync已添加到这些提交中的node.js:{{3} }

答案 6 :(得分:5)

您可以使用纤维来实现这一目标。例如,使用我的Common Node library,代码如下所示:

result = require('subprocess').command('node -v');

答案 7 :(得分:3)

我习惯在回调函数的末尾实现"synchronous"个东西。不是很好,但它的工作原理。如果需要实现一系列命令行执行,则需要将exec包装到某个命名函数中并递归调用它。 这种模式似乎对我有用:

SeqOfExec(someParam);

function SeqOfExec(somepParam) {
    // some stuff
    // .....
    // .....

    var execStr = "yourExecString";
    child_proc.exec(execStr, function (error, stdout, stderr) {
        if (error != null) {
            if (stdout) {
                throw Error("Smth goes wrong" + error);
            } else {
                // consider that empty stdout causes
                // creation of error object
            }
        }
        // some stuff
        // .....
        // .....

        // you also need some flag which will signal that you 
        // need to end loop
        if (someFlag ) {
            // your synch stuff after all execs
            // here
            // .....
        } else {
            SeqOfExec(someAnotherParam);
        }
    });
};

答案 8 :(得分:3)

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

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

  

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

使用说明位于ReadMe file。随意提出拉动请求或提交问题!

编辑: 然而它还没有返回标准输出...只是实时输出它们。 现在就这样做。好吧,我今天刚刚发布了它。也许我们可以建立它。

无论如何,我认为值得一提。

答案 9 :(得分:3)

原生Node.js解决方案是:

const {execSync} = require('child_process');

const result = execSync('node -v'); // ? this do the trick 

请注意,某些命令会返回 Buffer,而不是string。而且,如果您需要string,只需将encoding添加到execSync选项:

const result = execSync('git rev-parse HEAD', {encoding: 'utf8'});

...并且在同步执行程序上设置超时也很好:

const result = execSync('git rev-parse HEAD', {encoding: 'utf8', timeout: 10000});

答案 10 :(得分:1)

你可以在nodejs中执行同步shell操作,如下所示:

var execSync = function(cmd) {

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

    //for linux use ; instead of &&
    //execute your command followed by a simple echo 
    //to file to indicate process is finished
    exec(cmd + " > c:\\stdout.txt && echo done > c:\\sync.txt");

    while (true) {
        //consider a timeout option to prevent infinite loop
        //NOTE: this will max out your cpu too!
        try {
            var status = fs.readFileSync('c:\\sync.txt', 'utf8');

            if (status.trim() == "done") {
                var res = fs.readFileSync("c:\\stdout.txt", 'utf8');
                fs.unlinkSync("c:\\stdout.txt"); //cleanup temp files
                fs.unlinkSync("c:\\sync.txt");
                return res;
            }
        } catch(e) { } //readFileSync will fail until file exists
    }

};

//won't return anything, but will take 10 seconds to run
console.log(execSync("sleep 10")); 

//assuming there are a lot of files and subdirectories, 
//this too may take a while, use your own applicable file path
console.log(execSync("dir /s c:\\usr\\docs\\"));

编辑 - 此示例适用于Windows环境,必要时根据您自己的Linux需求进行调整

答案 11 :(得分:1)

我实际上有一种情况需要从package.json预安装脚本一个接一个地运行多个命令,这种方式可以在Windows和Linux / OSX上运行,所以我不能依赖非核心模块。

所以这就是我想出来的:

#cmds.coffee
childproc = require 'child_process'

exports.exec = (cmds) ->
  next = ->
    if cmds.length > 0
      cmd = cmds.shift()
      console.log "Running command: #{cmd}"
      childproc.exec cmd, (err, stdout, stderr) ->
        if err? then console.log err
        if stdout? then console.log stdout
        if stderr? then console.log stderr
        next()
    else
      console.log "Done executing commands."

  console.log "Running the follows commands:"
  console.log cmds
  next()

你可以像这样使用它:

require('./cmds').exec ['grunt coffee', 'nodeunit test/tls-config.js']

编辑:正如所指出的,这实际上并不返回输出或允许您使用Node程序中的命令结果。另一个想法是使用LiveScript后退。 http://livescript.net/