226

I need in node.js function

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! Still waiting for a more precise answer.

UPDATE

mgutz updated his answer and the solution is here :)
Also, as dgo.a mentioned, there is stand-alone module exec-sync

UPDATE 2014-07-30

ShellJS lib arrived. Consider this is the best choice for now.


UPDATE 2015-02-10

AT LAST! NodeJS 0.12 supports execSync natively.
See official docs

3
  • 36
    don't let yourself get fooled, sync is not wrong... EVEN in NodeJS all of your code is executed synchronously unless you explicitly call an async method ... if everything was done the asynchronous way nothing would ever be done. also, preferring asynchronous methods doesn't mean your lengthy calculation won't block your server. it's a choice. that the makers of Node chose to provide synchronous file system methods alongside the async ones just goes to show that there's a place for those, too. Commented Nov 16, 2013 at 16:01
  • 2
    Where can we find the "Unix shell emulation library" you are talking about? Commented Aug 9, 2014 at 14:52
  • @Florian he means ShellJS Commented Jun 28, 2015 at 18:39

14 Answers 14

230

Node.js (since version 0.12 - so for a while) supports 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). Note that you can also spawnSync now.

Sign up to request clarification or add additional context in comments.

5 Comments

How can I disconnect from this subprocess?
@JulianSoto nodejs.org/api/…
it returns <Buffer 76 31 31 2e 36 2e 30 0a> when i execSync('node -v'),what's that?
That’s a buffer, you can toString it
also: if you have a cmd that takes a bit longer to execute, you probably want to use it with the option { stdio: 'inherit' } to get real time console output. execSync('yourCmd', { stdio: 'inherit' })
56

See execSync library.

It's fairly easy to do with 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]

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

7 Comments

How would you go about actually getting anything sent to stdout from this? All I can get is the process exit code
@cwolves: I think async would be better this. (Ivo's answer)
@pvorb -- yeah, except when you can't use async :)
There are valid reasons for not using the async hammer for every nail. For example, template engines are async in Express 3 and helper functions (locals) need to be synchronous. What if those helper functions need to compile Less files asynchronously on the fly?
I wonder why this simple execSync is not part of child_process. I think, it should be.
|
32

Use ShellJS module.

exec function without providing callback.

Example:

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

3 Comments

Note that at the time of writing, the docs mention that the synchronous exec() is CPU intensive for long processes.
options, {silent:true} is key
This do something (other than provide shorter syntax) this doesn't? const execSync = require('child_process').execSync; code = execSync('node -v');
24

There's an excellent module for flow control in node.js called 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...');
});

3 Comments

He asked explicitly about sync version, not control flow libraries.
@AlexeyPetrushin Every question here is about a goal, not about particular way to achieve it. Thanks for downvoting though.
Also, this is a very useful answer for Windows users; installing exec-sync or ffi on Windows has a huge overhead (VC++, SDKs, Python, etc), but this is lighter.
17

Native Node.js solution is:

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. And if you need string just add encoding to execSync options:

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

Comments

9

This is not possible in Node.js, both child_process.spawn and child_process.exec were built from the ground up to be async.

For details see: 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.

Or, in case you have way too much time to spend, hack around in Node.js it self.

5 Comments

strange because the file system module has synchronous calls. Why not also execute?
@Alfred The sync FS calls are mainly in there for loading of configs at program start.
@IvoWetzel - tisk tisk... haven't we learned to never say something is impossible? ;) see my solution below.
@IvoWetzel "The sync FS calls..."—right, and sometimes you want to, say, issue a command to compile something at program start and continue on completion.—given that there are sync FS calls, not having a sync exec does look like an oversight. i'm all for asynchronous, but synchronous does have its pros and use cases. gotta use it in a judicious way, of course.
Async is fine, but if WidgetB depends on the final results of WidgetA, all the async in the world won't get the job done. Sometimes processes have to be synchronous. Try cooking asynchronously. ;)
9

This is the easiest way I found:

exec-Sync: https://github.com/jeremyfa/node-exec-sync
(Not to be confused with execSync.)
Execute shell command synchronously. Use this for migration scripts, cli programs, but not for regular server code.

Example:

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

Comments

9

Just to add that even though there are few usecases where you should use them, spawnSync / execFileSync / execSync were added to node.js in these commits: https://github.com/joyent/node/compare/d58c206862dc...e8df2676748e

2 Comments

Does this mean we going to have it in v0.12 out of the box?
6

my way since 5 years is to have 2 lines ;

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

Comments

5

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

Comments

3

I get used to implement "synchronous" stuff at the end of the callback function. 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. 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);
        }
    });
};

Comments

3

I had a similar problem and I ended up writing a node extension for this. You can check out the git repository. It's open source and free and all that good stuff !

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

2 Comments

This is exactly what I have been looking for. Thank you for putting in the time to make this.
The only thing I haven't figured out and implemented is the build configuration for different nodejs versions. I guess I wrote it on node 0.8 (travis-ci.org/aponxi/npm-execxi/builds/5248535) so as long as npm install succeeds (in other words as plugin compiles), then it is good to go for production. Besides targeting different nodejs versions, I'd say it's patched up for production, or that it's pretty stable. If there are any bugs you can send in a pull request or post an issue at github :)
1

you can do synchronous shell operations in nodejs like so:

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

6 Comments

Yes, and as fast as your CPU can possibly summon... But hey when you "need" to do something evil, Satan's your man right?
ok, this is pure evil, but awesome. I needed this to handle a filesystem event browserify.on('register'), that did not have a callback. Saved my day!
can you explain why this works on javascript engines? shouldn't the while loop be executed infinitely on the same tick while exec executes on the next one?
Maxing out the CPU by busy waiting is bad design.
@Louis-DominiqueDubeau Sure, but there isn't really any alternative that doesn't depend on some third party source that may or may not be cross platform compatible. It's also not a true maxing out of the CPU because the OS won't give full priority to the nodejs process. I think sync implementations of shell ops are on the horizon or perhaps here already.
|
1

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.

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. One other idea for that is to use LiveScript backcalls. http://livescript.net/

2 Comments

Thanks, but this is not an answer since your code runs commands in series asynchronously
If you need to execute a series of commands synchronously as per my example it will work. I think I misunderstood your question though, sorry. I added another idea to the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.