Error getting the output of child process in node - node.js

I have a c program (I didn't code it) that prints some data in the terminal. I launch the program as a child process in node with the spawn function.
const child_process = spawn('./myProgram', ['--arg']);
After that, I code the event to get the printed data:
child_process.stdout.on('data', function(data) {
console.log(data);
});
When I run the program I can't see the output data from my c program in my nodejs terminal. If I initialize the child process with stdio as inherit it works.
const child_process = spawn('./myProgram', ['--arg'], {stdio :'inherit'});
The key point here is that I need to process that data in my nodejs app. I suppose the way the c file prints the data is not the standard one, so my nodjs program does not get it.

The file was outputting to stderr instead to stdout. It was fixed by adding the event to stderr:
child_process.stderr.on('data', function(data) {
console.log(data);
});
#tadman got the answere.

Related

Electron.js - Send child process' spawn stdout data to renderer in realtime

I have a simple node child process that invokes a script and that script takes time to output some information (kinda like how ping works).
let command = spawn(
execPath,
[...args],
{ cwd: null, detached: false }
);
Then I do a standard console.log for the stdout:
command.stdout.on("data", (stdout) => {
console.log("Realtime Output: ", stdout.toString());
});
The issue is, I want to send this realtime output back to renderer process and show it on the frontend. I tried adding an ipcRenderer.send() inside the command.stdout.on() but it doesn't work, and the frontend shows undefined in console.log.
Is there any way to achieve this?
You have to send the stdout from mainWindow through webContents
mainWindow.webContents.send('output', stdout.toString())

Can I “listen” for a specific output with child_process?

So far I have gotten my script to execute a windows .bat file with child_process, my issue is that it opens it in the background with no way to “connect” to it to see what happens and debug, is there a way to “listen” for a certain output to happen? For example, if the .bat outputs a “Done!” in the shell at one point, is there a way to make my node.js script detect that certain keyword and run further commands if it does?
Thanks!
Some clarification: The .bat outputs "Done!" and stays running, it doesn't stop, all I want to do is detect that "Done!" so that I can send a message to the user that the server has successfully started
My current code:
exec('D:\\servers\\game_server_1\\start.bat', {shell: true, cwd: 'D:\\servers\\game_server_1'});
Well, if you're trying to do a one and done type of NodeJS script, you can just spawn a process that launches with the given command and exits when all commands completed. This creates a one and done streaming interface that you can monitor. The stdout returns a data buffer that returns the command you ran, unless it's something like START to launch a program-- it returns null. You could just issue a KILL command after the START -- your_program.exe:
const spawn = require('child_process').spawn;
const child = spawn('cmd.exe', ['/c', 'commands.bat']);
let DONE = 0;
const done = () => {
console.log("log it");
DONE++;
};
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
//it's important to add some type of counter to
//prevent any logic from running twice, since
//this will run twice for any given command
if ( data.toString().includes("DONE") && DONE === 0 ) {
done();
}
});
child.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
child.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
Keep in mind, when you run a command to launch a program and the program launches, the data buffer will be null in stdout event listener. The error event will only fire if there was an issue with launching the program.
YOUR .BAT:
ECHO starting batch script
//example launching of program
START "" https://localhost:3000
//issue a command after your program launch
ECHO DONE
EXIT
You could also issue an ECHO DONE command right after the command where you launched the program and listen for that, and try and parse out that command from stdout.
You could use a Regular expression.
const { spawn } = require('child_process');
const child = spawn(...);
child.stdout.on('data', function (data) {
console.log('stdout: ' + data);
// Now use a regular expression to detect a done event
// For example
data.toString().match(/Done!/);
});
// Error handling etc. here

The mechanism behind WritableStream.write and data event in Node

I'll illustrate the problem with the following code.
child.js :
process.stdin.resume();
process.stdin.on('data', function(data) {
process.stdout.write(data + '\n');
process.stdout.write('world\n');
process.stdout.write('greatings, earthlings!\n');
});
parent.js :
var spawn = require('child_process').spawn;
var child = spawn('node', ['child.js']);
child.stdin.write('hello');
child.stdout.on('data', function(data) {
process.stdout.write('child echoed with: ' + data);
});
And in the Windows cmd, I run
node parent.js
it outputs:
child echoed with: hello
child echoed with: world
greatings, earthlings!
Here I did bind the data event on every child's stdout, and I shall get echoed back in a pattern as 'child echoed with data'.
As you can see, on the third line of the outputs, it's not in that pattern. So why?
I assume one write triggers one data event(true?).
So I tried to signify when does the data event callback function end.
I changed the way I bind data event in parent.js with:
child.stdout.on('data', function(data) {
process.stdout.write('child echoed with: ' + data);
process.stdout.write('callback ends\n');
});
And I get this output:
child echoed with: hello
callback ends
child echoed with: world
greatings, earthlings!
callback ends
It turns out with three write, only two data events get fired?
So why this is happening?
A stream is just a stream of bytes, so it is not safe to assume there will be any correlation between the number of write calls and the number of data events. For standard implementations and usage, chances are that they will be close to the same, but it depends on how quickly you are writing the data, and how much data you are writing. For instance, one call to write could trigger a data event for each byte written, or some number of write calls could be buffered before data is emitted.
To be clear, what is happening in your case is this:
process.stdout.write(data + '\n');
// Emits 'data' event with "hello\n"
process.stdout.write('world\n');
// Doesn't emit 'data' because it is buffered somewhere.
process.stdout.write('greatings, earthlings!\n');
// Emits 'data' event with "world\ngreatings, earthlings!\n"
So that second event has two lines. Which means when you run
process.stdout.write('child echoed with: ' + data)
you are printing exactly what you see:
child echoed with: world\ngreatings, earthlings!\n
which renders as
child echoed with: world
greatings, earthlings!

How can I execute a node.js module as a child process of a node.js program?

Here's my problem. I implemented a small script that does some heavy calculation, as a node.js module. So, if I type "node myModule.js", it calculates for a second, then returns a value.
Now, I want to use that module from my main Node.JS program. I could just put all the calculation in a "doSomeCalculation" function then do:
var myModule = require("./myModule");
myModule.doSomeCalculation();
But that would be blocking, thus it'd be bad. I'd like to use it in a non-blocking way, like DB calls natively are, for instance. So I tried to use child_process.spawn and exec, like this:
var spawn = require("child_process").spawn;
var ext = spawn("node ./myModule.js", function(err, stdout, stderr) { /* whatevs */ });
ext.on("exit", function() { console.log("calculation over!"); });
But, of course, it doesn't work. I tried to use an EventEmitter in myModule, emitting "calculationDone" events and trying to add the associated listener on the "ext" variable in the example above. Still doesn't work.
As for forks, they're not really what I'm trying to do. Forks would require putting the calculation-related code in the main program, forking, calculating in the child while the parent does whatever it does, and then how would I return the result?
So here's my question: can I use a child process to do some non-blocking calculation, when the calculation is put in a Node file, or is it just impossible? Should I do the heavy calculation in a Python script instead? In both cases, how can I pass arguments to the child process - for instance, an image?
I think what you're after is the child_process.fork() API.
For example, if you have the following two files:
In main.js:
var cp = require('child_process');
var child = cp.fork('./worker');
child.on('message', function(m) {
// Receive results from child process
console.log('received: ' + m);
});
// Send child process some work
child.send('Please up-case this string');
In worker.js:
process.on('message', function(m) {
// Do work (in this case just up-case the string
m = m.toUpperCase();
// Pass results back to parent process
process.send(m.toUpperCase(m));
});
Then to run main (and spawn a child worker process for the worker.js code ...)
$ node --version
v0.8.3
$ node main.js
received: PLEASE UP-CASE THIS STRING
It doesn't matter what you will use as a child (Node, Python, whatever), Node doesn't care. Just make sure, that your calculcation script exits after everything is done and result is written to stdout.
Reason why it's not working is that you're using spawn instead of exec.

Output using util.format on Node.js child process is not shown when done before process.exit()

I do have a node application that starts one. I am using the spawn() method instead of fork() to create the child instance because I sometimes need to start the child process using different node command line arguments (e.g. debug).
Consider the following example:
master.js
var child = require("child_process").spawn("node", ["child"]);
child.stdout.pipe(process.stdout, { end: false });
child.js
console.log("Hello World!");
console.log(require("util").format("Hello World2!"));
setTimeout(function(){
console.log("Error!");
console.log(require("util").format("Error2!"));
process.exit(1);
},2000);
When running master.js (on windows) the actual output is
Hello World!
Hello World2!
Error!
The "Error2!" message is missing and I don't understand why. Do you have any idea what's going wrong here?
Thanks in advance!

Resources