brandonscript
brandonscript

Reputation: 72865

Retrieve shell error output from child_process.spawn

I'm using child_process.spawn and need to capture the shell error that occurs when the command fails. According to this question, I should be able to do:

var child_process = require('child_process');

var python = child_process.spawn(
    'python', ["script.py", "someParam"]
);
python.on('error', function(error) {
    console.log("Error: bad command", error);
});

When I replace 'python', ["script.py", "someParam"] with banana, like in the linked question, it works, and the error is visible. But in my case, using python with arguments, the 'error' event is never called.

How can I capture shell errors from python?

Upvotes: 5

Views: 5170

Answers (2)

Đumić Branislav
Đumić Branislav

Reputation: 387

Thread is a little bit old and all but I encountered this today while working on my test casing library. I realize that the accepted answer has a solution already, but, for me, it is not clearly explained. Anyway in case someone needs it here is what you need to do.

The thing I realized is that, while executing code, if python interpreter encounters an error, or should I say, if your code has an error in it, it will write it to standard error stream and exit. So what you need to do, in your Node.js code, is to listen to the stderr stream of the spawned process. In addition, all of the data passed to print() function is written to the 'stdout' stream of the process.

So here is an example code:

  const { spawn } = require('child_process');
  const proc = spawn('python',['main.py','-c']);

  proc.stderr.on('data',(data)=>{
    //Here data is of type buffer
    console.log(data.toString())
  })

  proc.stdout('data',(data)=>{
    //Also buffer
    console.log(data.toString());
  })

What happens here should already be clear if you read the first part of my answer. One other thing you could do instead of writing data to the console, is redirect it to another stream, this could be really useful if you want to write output data to a file for example. This is how you could do it:

   const fs = require('fs');
   const path = require('path');
   const { spawn } = require('child_process');

   const outputFile = path.join(__dirname,'stdout.txt');
   const errorFile = path.join(__dirname,'stderr.txt');

   const outputStream = fs.createWriteStream(outputFile, {
     encoding: "utf8",
     autoClose: true
   });

   const outputStream = fs.createWriteStream(errorFile, {
     encoding: "utf8",
     autoClose: true
   });   

   const proc = spawn('python',['main.py','-c']);
   proc.stdout.pipe(outputStream);
   proc.stderr.pipe(errorStream);

What is happening here is that, using pipe function we send all data from stdout and stderr of the process to the file streams. Also you do not have to worry about files existing, it will create them for you

Upvotes: 3

Trott
Trott

Reputation: 70065

According to the Node.js docs for the ChildProcess error event, it is only fired in a few situations:

  1. The process could not be spawned, or
  2. The process could not be killed, or
  3. Sending a message to the child process failed for whatever reason.

To capture the shell error output, you can additionally listen to data events on the stdout and stderr of your spawned process:

python.stdout.on('data', function(data) {
    console.log(data.toString()); 
});

python.stderr.on('data', function(data) {
    console.error(data.toString());
});

To capture the shell error code, you can attach a listener to the exit event:

python.on('exit', function(code) {
    console.log("Exited with code " + code);
});

Upvotes: 7

Related Questions