【问题标题】:node.js execute system command synchronouslynode.js 同步执行系统命令
【发布时间】:2011-05-25 12:32:33
【问题描述】:

我需要 node.js 函数

result = execSync('node -v');

这将同步执行给定的命令行并返回该命令文本的所有标准输出。

ps。同步错误。我知道。仅供个人使用。

更新

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

更新

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

2014 年 7 月 30 日更新

ShellJS lib 到了。认为这是目前最好的选择。


2015 年 2 月 10 日更新

终于! NodeJS 0.12 原生支持 execSync
见官方docs

【问题讨论】:

  • 别让自己上当了,同步并没有错……即使在 NodeJS 中,你的所有代码都会同步执行,除非你显式调用异步方法……如果 everything i> 以异步方式完成 nothing 永远不会完成。此外,更喜欢异步方法并不意味着您的冗长计算不会阻塞您的服务器。这是一个选择。 Node 的制造商选择提供同步文件系统方法和异步文件系统方法只是表明这些方法也有一席之地。
  • 在哪里可以找到您所说的“Unix shell 仿真库”?
  • @Florian 他的意思是ShellJS

标签: javascript command node.js exec sync


【解决方案1】:

Node.js(从 0.12 版开始 - 暂时如此)支持execSync

child_process.execSync(command[, options])

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

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

它会做你所期望的。 (默认将 i/o 结果通过管道传输到父进程)。请注意,您现在也可以spawnSync

【讨论】:

  • 在 10 个小时的绝望之后。谢谢老兄
  • 如何断开与这个子进程的连接?
  • @JulianSoto nodejs.org/api/…
  • 当我 execSync('node -v') 时它返回 ,那是什么?
  • 那是一个缓冲区,你可以把它串起来
【解决方案2】:

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

【讨论】:

  • 您将如何实际将任何东西从这里发送到stdout?我能得到的只是进程退出代码
  • @cwolves:我认为异步会更好。 (Ivo's answer)
  • @pvorb -- 是的,除非你不能使用异步 :)
  • 有正当理由不使用异步锤子来处理每个钉子。例如,Express 3 中的模板引擎是异步的,辅助函数(本地)需要同步。如果这些辅助函数需要实时异步编译 Less 文件怎么办?
  • 我想知道为什么这个简单的execSync 不是child_process 的一部分。我想,应该是的。
【解决方案3】:

使用ShellJS 模块。

exec 函数不提供回调。

例子:

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

【讨论】:

  • 请注意,在撰写本文时,文档提到同步 exec() 对于长进程来说是 CPU 密集型的。
  • 选项,{silent:true} 是关键
  • 这会做一些事情(除了提供更短的语法)这不是吗? const execSync = require('child_process').execSync; code = execSync('node -v');
【解决方案4】:

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

【讨论】:

  • 他明确询问了同步版本,而不是控制流库。
  • @AlexeyPetrushin 这里的每个问题都是关于目标的,而不是关于实现目标的特定方式。感谢您的反对。
  • 另外,这对 Windows 用户来说是一个非常有用的答案;在 Windows 上安装 exec-syncffi 会产生巨大的开销(VC++、SDK、Python 等),但这更轻。
【解决方案5】:

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

详情见:https://github.com/ry/node/blob/master/lib/child_process.js

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

或者,如果你有太多时间可以花在 Node.js 中,那就自己动手吧。

【讨论】:

  • 很奇怪,因为文件系统模块有同步调用。为什么不也执行?
  • @Alfred 同步 FS 调用主要用于在程序启动时加载配置。
  • @IvoWetzel - tisk tisk...我们没有学会永远不要说某事是不可能的吗? ;) 请参阅下面的解决方案。
  • @IvoWetzel “同步 FS 调用...”——对,有时你想,比如说,在程序开始时发出一个命令来编译一些东西,并在完成时继续。——假设有同步FS 调用,没有同步 exec 看起来确实像一个疏忽。我完全支持异步,但同步确实有其优点和用例。当然,必须以明智的方式使用它。
  • Async 没问题,但是如果 WidgetB 依赖于 WidgetA 的最终结果,那么世界上所有的 async 都无法完成工作。有时流程必须是同步的。尝试异步烹饪。 ;)
【解决方案6】:

这是我找到的最简单的方法:

执行同步https://github.com/jeremyfa/node-exec-sync
(不要与 execSync 混淆。)
同步执行shell命令。将此用于迁移脚本、cli 程序,但不适用于常规服务器代码。

例子:

var execSync = require('exec-sync');   
var user = execSync('echo $USER');
console.log(user);

【讨论】:

    【解决方案7】:

    只是补充一点,即使您应该使用它们的用例很少,spawnSync / execFileSync / execSync 在这些提交中添加到 node.js:https://github.com/joyent/node/compare/d58c206862dc...e8df2676748e

    【讨论】:

    【解决方案8】:

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

    【讨论】:

    • {encoding: 'utf8'} 这就是我要找的,谢谢。
    【解决方案9】:

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

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

    【讨论】:

      【解决方案10】:

      我习惯在回调函数的末尾实现"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);
              }
          });
      };
      

      【讨论】:

        【解决方案11】:

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

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

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

        使用说明在ReadMe file 中。随意提出拉取请求或提交问题!

        编辑: 但是它还没有返回标准输出...只是实时输出它们。 现在可以了。嗯,我今天刚发布。也许我们可以以此为基础。

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

        【讨论】:

        • 这正是我一直在寻找的。感谢您花时间制作这个。
        • 我唯一没有弄清楚并实现的是不同nodejs版本的构建配置。我想我是在节点 0.8 (travis-ci.org/aponxi/npm-execxi/builds/5248535) 上写的,所以只要 npm install 成功(换句话说,插件编译),那么就可以进行生产了。除了针对不同的 nodejs 版本之外,我想说它已经为生产进行了修补,或者它非常稳定。如果有任何错误,您可以发送拉取请求或在 github 上发布问题 :)
        【解决方案12】:

        您可以像这样在 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 需求进行调整

        【讨论】:

        • 是的,而且你的 CPU 可能会以最快的速度召唤......但是,当你“需要”做一些邪恶的事情时,撒旦是你的人,对吧?
        • 好的,这是纯粹的邪恶,但很棒。我需要它来处理没有回调的文件系统事件 browserify.on('register')。拯救了我的一天!
        • 您能解释一下为什么这适用于 javascript 引擎吗? while 循环不应该在同一个滴答声上无限执行,而 exec 在下一个滴答声上执行吗?
        • 通过忙等待来最大化 CPU 是糟糕的设计。
        • @Louis-DominiqueDubeau 当然,但实际上没有任何替代方案不依赖于可能兼容或不兼容跨平台的第三方来源。这也不是真正的 CPU 最大化,因为操作系统不会完全优先考虑 nodejs 进程。我认为 shell 操作的同步实现即将出现,或者可能已经出现了。
        【解决方案13】:

        我实际上遇到了一种情况,我需要从 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/

        【讨论】:

        • 谢谢,但这不是答案,因为您的代码异步串行运行命令
        • 如果您需要按照我的示例同步执行一系列命令,它将起作用。我想我误解了你的问题,对不起。我在答案中添加了另一个想法。
        【解决方案14】:

        我 5 年来的方式是有 2 行;

        const { execSync } = require('child_process');
        const shell = (cmd) => execSync(cmd, {encoding: 'utf8'});
        

        然后享受: shell('git remote -v') 要么 out = shell('ls -l') ..等等

        【讨论】:

          猜你喜欢
          • 2013-05-22
          • 2011-11-03
          • 2021-09-07
          • 2011-10-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多