13

I like to integrate exec from nodejs in a custom function to handle all the errors in this one function.

const exec = require('child_process').exec;

function os_func() {
    this.execCommand = function(cmd) {
        var ret;
        exec(cmd, (error, stdout, stderr) => {
            if (error) {
                console.error(`exec error: ${error}`);
                return;
            }
            ret = stdout;
        });
        return ret;
    }
}
var os = new os_func();

This function returns undefined because exec isn't finished when the value returns. How can i solve that? Can i force the function to wait for exec?

RGe
  • 1,181
  • 1
  • 10
  • 19
  • Does this answer your question? [How to return the response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-to-return-the-response-from-an-asynchronous-call) – ggorlen Apr 01 '22 at 04:40

6 Answers6

14

you can use promise as :

const exec = require('child_process').exec;

function os_func() {
    this.execCommand = function (cmd) {
        return new Promise((resolve, reject)=> {
           exec(cmd, (error, stdout, stderr) => {
             if (error) {
                reject(error);
                return;
            }
            resolve(stdout)
           });
       })
   }
}
var os = new os_func();

os.execCommand('pwd').then(res=> {
    console.log("os >>>", res);
}).catch(err=> {
    console.log("os >>>", err);
})
Sourbh Gupta
  • 808
  • 7
  • 16
12

Since the command is executed asynchronously you will want to use a callback to handle the return value once the command has finished executing:

const exec = require('child_process').exec;

function os_func() {
    this.execCommand = function(cmd, callback) {
        exec(cmd, (error, stdout, stderr) => {
            if (error) {
                console.error(`exec error: ${error}`);
                return;
            }

            callback(stdout);
        });
    }
}
var os = new os_func();

os.execCommand('SomeCommand', function (returnvalue) {
    // Here you can get the return value
});
Hyddan
  • 1,297
  • 15
  • 24
12

Yet another solution using ES6 modules:

import fs from "node:fs";
import {exec} from "node:child_process";
import util from "node:util";

// promisify exec
const execPromise = util.promisify(exec);

try {
  // wait for exec to complete
  const {stdout, stderr} = await execPromise("ls -l");
} catch (error) {
  console.log(error);
}
8ctopus
  • 2,617
  • 2
  • 18
  • 25
6

exec will deal with it in an async fashion, so you should receive a callback or return a promise.

One thing you could do in order to make it sync is to use execSync instead:

https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options

The child_process.execSync() method is generally identical to child_process.exec() with the exception that the method will not return until the child process has fully closed. When a timeout has been encountered and killSignal is sent, the method won't return until the process has completely exited. Note that if the child process intercepts and handles the SIGTERM signal and doesn't exit, the parent process will wait until the child process has exited.

yokomizor
  • 1,527
  • 1
  • 19
  • 20
4

Adding what worked for me, as none of the above did the trick!

const { exec } = require("child_process");
const util  = require("util");
const execPromise = util.promisify(exec);

function parentFunction() {
...
  // Trigger 'exec', then a-wait for it to finish
  await execWrapper('<your-command-here>');
...
}

...
async function execWrapper(cmd) {
  const { stdout, stderr } = await execPromise(cmd);
  if (stdout) {
    console.log(`stderr: ${stdout}`);
  }
  if (stderr) {
    console.log(`stderr: ${stderr}`);
  }
}

NOTE: This isn't your example, but just a generic one; for me - the cmd was a Docker build command. You could probably have execWrapper return back the stdout if needed.

Neil P.
  • 1,026
  • 2
  • 15
  • 32
0

You can do it with callback. Maybe you can try something like this:

function os_func() {
this.execCommand = function(cmd, myCallback) {
    var ret;
    exec(cmd, (error, stdout, stderr) => {
        if (error) {
            console.error(`exec error: ${error}`);
            return;
        }
        ret = stdout;
        myCallback(ret);

    });
}


function myCallback(ret){
      // TODO: your stuff with return value...
}
Dejan Dimčić
  • 294
  • 1
  • 3
  • 9