简体   繁体   English

node.js 同步执行系统命令

[英]node.js execute system command synchronously

I need in node.js function我需要在node.js函数中

result = execSync('node -v');

that will synchronously execute the given command line and return all stdout'ed by that command text.这将同步执行给定的命令行并返回该命令文本的所有标准输出。

ps.附: Sync is wrong.同步错误。 I know.我知道。 Just for personal use.仅供个人使用。

UPDATE更新

Now we have mgutz's solution which gives us exit code, but not stdout!现在我们有了 mgutz 的解决方案,它为我们提供了退出代码,但没有标准输出! Still waiting for a more precise answer.仍在等待更准确的答案。

UPDATE更新

mgutz updated his answer and the solution is here :) mgutz更新了他的答案,解决方案在这里:)
Also, as dgo.a mentioned, there is stand-alone module exec-sync另外,正如dgo.a提到的,有独立模块exec-sync

UPDATE 2014-07-30更新 2014-07-30

ShellJS lib arrived. ShellJS库到了。 Consider this is the best choice for now.考虑到这是目前最好的选择。


UPDATE 2015-02-10更新 2015-02-10

AT LAST!最后! NodeJS 0.12 supports execSync natively. execSync 0.12 原生支持execSync
See official docs查看官方文档

Node.js (since version 0.12 - so for a while) supports execSync : Node.js(从 0.12 版开始 - 所以有一段时间)支持execSync

child_process.execSync(command[, options])

You can now directly do this:您现在可以直接执行此操作:

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

and it'll do what you expect.它会做你所期望的。 (Defaults to pipe the i/o results to the parent process). (默认将 i/o 结果通过管道传输到父进程)。 Note that you can also spawnSync now.请注意,您现在也可以spawnSync

See execSync library.请参阅execSync库。

It's fairly easy to do with node-ffi .使用node-ffi相当容易。 I wouldn't recommend for server processes, but for general development utilities it gets things done.我不会推荐服务器进程,但对于一般的开发实用程序,它可以完成工作。 Install the library.安装库。

npm install node-ffi

Example script:示例脚本:

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

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

[EDIT Jun 2012: How to get STDOUT] [编辑 2012 年 6 月:如何获得标准输出]

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

Use ShellJS module.使用ShellJS模块。

exec function without providing callback. exec函数而不提供回调。

Example:示例:

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

There's an excellent module for flow control in node.js called asyncblock . node.js 中有一个出色的流量控制模块,称为asyncblock If wrapping the code in a function is OK for your case, the following sample may be considered:如果将代码包装在函数中适合您的情况,则可以考虑以下示例:

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

This is the easiest way I found:这是我找到的最简单的方法:

exec-Sync : https://github.com/jeremyfa/node-exec-sync执行同步https : //github.com/jeremyfa/node-exec-sync
(Not to be confused with execSync.) (不要与 execSync 混淆。)
Execute shell command synchronously.同步执行shell命令。 Use this for migration scripts, cli programs, but not for regular server code.将此用于迁移脚本、cli 程序,但不适用于常规服务器代码。

Example:示例:

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

This is not possible in Node.js, both child_process.spawn and child_process.exec were built from the ground up to be async.这在 Node.js 中是不可能的, child_process.spawnchild_process.exec都是child_process.exec开始构建为异步的。

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

If you really want to have this blocking, then put everything that needs to happen afterwards in a callback, or build your own queue to handle this in a blocking fashion, I suppose you could use Async.js for this task.如果你真的想要这个阻塞,那么把之后需要发生的所有事情都放在回调中,或者构建你自己的队列以阻塞方式处理这个,我想你可以使用Async.js来完成这个任务。

Or, in case you have way too much time to spend, hack around in Node.js it self.或者,如果您有太多时间可以花,可以自己在 Node.js 中进行破解。

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

Native Node.js solution is:原生 Node.js 解决方案是:

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

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

Just be aware that some commands returns Buffer instead of string .请注意,某些命令返回Buffer而不是string And if you need string just add encoding to execSync options:如果您需要string只需将encoding添加到 execSync 选项:

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

... and it is also good to have timeout on sync exec: ...并且同步执行超时也很好:

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

You can achieve this using fibers.您可以使用纤维来实现这一点。 For example, using my Common Node library , the code would look like this:例如,使用我的公共节点库,代码如下所示:

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

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!随意提出请求请求或提交问题!

EDIT: However it doesn't return the stdout yet... Just outputs them in real-time. 编辑: 但是它还没有返回标准输出......只是实时输出它们。 It does now.现在确实如此。 Well, I just released it today.嗯,我今天刚发布。 Maybe we can build on it.也许我们可以以此为基础。

Anyway, I thought it was worth to mention it.无论如何,我认为值得一提。

I get used to implement "synchronous" stuff at the end of the callback function.我习惯于在回调函数的末尾实现"synchronous"东西。 Not very nice, but it works.不是很好,但它有效。 If you need to implement a sequence of command line executions you need to wrap exec into some named function and recursively call it.如果您需要实现一系列命令行执行,您需要将exec包装到某个命名函数中并递归调用它。 This pattern seem to be usable for me:这种模式似乎对我有用:

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

I actually had a situation where I needed to run multiple commands one after another from a package.json preinstall script in a way that would work on both Windows and Linux/OSX, so I couldn't rely on a non-core module.我实际上遇到过这样的情况,我需要从 package.json 预安装脚本中一个接一个地运行多个命令,这种方式可以在 Windows 和 Linux/OSX 上运行,所以我不能依赖非核心模块。

So this is what I came up with:所以这就是我想出的:

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

You can use it like this:你可以这样使用它:

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

EDIT: as pointed out, this doesn't actually return the output or allow you to use the result of the commands in a Node program.编辑:正如所指出的,这实际上并不返回输出或允许您在 Node 程序中使用命令的结果。 One other idea for that is to use LiveScript backcalls.另一个想法是使用 LiveScript 回拨。 http://livescript.net/ http://livescript.net/

you can do synchronous shell operations in nodejs like so:您可以像这样在 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\\"));

EDIT - this example is meant for windows environments, adjust for your own linux needs if necessary编辑 - 此示例适用于 Windows 环境,如有必要,请根据您自己的 linux 需求进行调整

my way since 5 years is to have 2 lines ;我 5 年来的方式是拥有 2 条线;

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

Then enjoy: shell('git remote -v') or out = shell('ls -l') .. so on然后享受: shell('git remote -v')out = shell('ls -l') .. 等等

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

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