36

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 Answers5

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) });
Zearin
  • 1,474
  • 2
  • 17
  • 36
fuwaneko
  • 1,155
  • 8
  • 10
  • Thanks! How would I change it to have the function output to a variable instead of console.log? – Billions McMillions Mar 20 '13 at 05:18
  • 1
    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: https://github.com/caolan/async#series. But ask yourself why you want to do that. – fuwaneko Mar 21 '13 at 13:52
  • 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 – GrayedFox Mar 05 '18 at 05:24
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.

Community
  • 1
  • 1
Marcel
  • 1,266
  • 7
  • 18
4

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) })
    })
}
Nelson Owalo
  • 2,324
  • 18
  • 37
  • I tried this solution while working with the `ping` command and it didn't work. @fuwaneko's solution worked for me, however. – Vince Mar 20 '21 at 04:19
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
}
Mohammad Yaser Ahmadi
  • 4,664
  • 3
  • 17
  • 39
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')
Joseph Merdrignac
  • 3,510
  • 2
  • 19
  • 16