37

I'm trying to return the output of this function as a string, but it keeps returning as undefined. Where am I going wrong?

function run(cmd){
    var spawn = require('child_process').spawn;
    var command = spawn(cmd);
    var result = '';
    command.stdout.on('data', function(data) {
            result += data.toString();
    });
    command.on('close', function(code) {
            return result;
    });
}
console.log(run('ls'));

5 Answers 5

52

Your function returns immediately after command.on statement. The return statement in your callback for the close event is returned to nowhere. The return belongs to event callback, not to run().

Put console.log call instead of return result.

Generally speaking you should write something like:

function run(cmd, callback) {
    var spawn = require('child_process').spawn;
    var command = spawn(cmd);
    var result = '';
    command.stdout.on('data', function(data) {
         result += data.toString();
    });
    command.on('close', function(code) {
        return callback(result);
    });
}

run("ls", function(result) { console.log(result) });
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks! How would I change it to have the function output to a variable instead of console.log?
You should do whatever you have to do with command result in callback function, just replace console.log with real code. Everything is asynchronous, so even if you try to put result value in a global variable you can't tell when it'll be available. If you really want to do something in non-async way this could help: github.com/caolan/async#series. But ask yourself why you want to do that.
Waaaah I'm so silly. Was resolving my promises on child.stdout.on('data', data) and wondering why my output was incomplete and randomly truncated. If you're experiencing that problem store the data into a variable first which is resolved/rejected inside your child.on('close') event as in this answer. Thanks @fuwaneko
5
var spawn = require('child_process').spawn,
    command  = spawn('ls', ['/tmp/']);
command.stdout.pipe(process.stdout);

The following link is exactly the same question as yours.

2 Comments

clever, but he probably wants to do moer then just print the result to process.stdout
Thanks for the answer. How would I store stdout.pipe into a variable?
5

You can always wrap your function in a promise and return that. I find more efficient than @fuwaneko's callback solution

function run(cmd) {
    return new Promise((resolve, reject) => {
        var spawn = require('child_process').spawn;
        var command = spawn(cmd)
        var result = ''
        command.stdout.on('data', function(data) {
             result += data.toString()
        })
        command.on('close', function(code) {
            resolve(result)
        })
        command.on('error', function(err) { reject(err) })
    })
}

1 Comment

I tried this solution while working with the ping command and it didn't work. @fuwaneko's solution worked for me, however.
0

clean way is using async/await so try like this:

const spawn = require('child_process').spawnSync;
 
try {
    const child = spawn(cmd)
    return { stdout: child.stdout.toString(), stderr: child.stderr.toString() }
} catch (error) {
    console.log(error);
    return error
}

3 Comments

and where is async/await?
@srghma in the first line of code I required spawnSync then do not need to using async/await
Why did you replace spawnSync with spawn? It is confusing because there exists a spawn method by itself.
0

Typescript version:
(following common current async usage)

import { spawn } from 'child_process'

const run = (commandLine: string) => new Promise<string>((resolve, reject) => {
  const [command, ...args] = commandLine.split(/\s+/)
  const child = spawn(command, args)
  const output = [] as string[]
  child.stdout.on('data', chunk => output.push(chunk))
  child.on('close', () => resolve(output.join('').trim()))
  child.on('error', error => reject(error))
})

usage:

const branch = await run('git branch --show-current')

Comments

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.