Description
I'd like to have a nodejs script interact with a child process via standard input and output. I've tried setting this up with what the documentation provides, but I've arrived at a deadlock where what's happening doesn't match what's I believe is documented.
What I see in the documentation:
The ChildProcess class is not intended to be used directly. Use the spawn(), exec(), execFile(), or fork() methods to create a Child Process instance.
Reading each section leads me to:
- spawn: Create a child process from any normal terminal program, and have access to stdio.
- exec: Create a child process from any normal terminal program, and receive output on exit.
- execFile: Similar to exec but for an explicit executable file, receive output on exit.
- fork: Create a new node instance from any proper nodejs file, interact using messages.
The section for spawn describes access to an stdio
option. Looking further up the page, I read that the child's stdin and stdout both default to a writeable or readable stream.
OK, I don't entirely know what a stream is in the context of Node, so looking at the stream doc page:
Readable streams have two "modes": a flowing mode and a paused mode. When in flowing mode, data is read from the underlying system and provided to your program as fast as possible.
Cool, and then since I've already looked at the child-process.spawn examples, I know that .on('data'...
is important. It's listed right below:
Attaching a data event listener to a stream that has not been explicitly paused will switch the stream into flowing mode. Data will then be passed as soon as it is available.
If you just want to get all the data out of the stream as fast as possible, this is the best way to do so.
This looks pretty straightforward, I want spawn
. This child process of mine will persist for a while, and I want access to the output as it appears. Sounds like a good match.
Running the provided example:
Great, time to become familiar with the .spawn
operator. To do so, I'll run the provided ps ax | grep ssh
example:
var spawn = require('child_process').spawn,
ps = spawn('ps', ['ax']),
grep = spawn('grep', ['ssh']);
ps.stdout.on('data', function (data) {
grep.stdin.write(data);
});
ps.stderr.on('data', function (data) {
console.log('ps stderr: ' + data);
});
ps.on('close', function (code) {
if (code !== 0) {
console.log('ps process exited with code ' + code);
}
grep.stdin.end();
});
grep.stdout.on('data', function (data) {
console.log('' + data);
});
grep.stderr.on('data', function (data) {
console.log('grep stderr: ' + data);
});
grep.on('close', function (code) {
if (code !== 0) {
console.log('grep process exited with code ' + code);
}
});
Output:
$ node grep.js
6364 pts/0 S+ 0:00 ssh bns-xwing-local
It works!
Running a modified example:
But I notice that grep exits pretty quickly. I want my program to persist, so I'm going to modify the example to leave grep running for a while longer.
var spawn = require('child_process').spawn,
ps = spawn('ps', ['ax']),
grep = spawn('grep', ['ssh']);
ps.stdout.on('data', function (data) {
grep.stdin.write(data);
});
ps.stderr.on('data', function (data) {
console.log('ps stderr: ' + data);
});
ps.on('close', function (code) {
if (code !== 0) {
console.log('ps process exited with code ' + code);
}
/* ---------------------------------------- */
//grep.stdin.end(); /* <- Only line changed */
/* ---------------------------------------- */
});
grep.stdout.on('data', function (data) {
console.log('' + data);
});
grep.stderr.on('data', function (data) {
console.log('grep stderr: ' + data);
});
grep.on('close', function (code) {
if (code !== 0) {
console.log('grep process exited with code ' + code);
}
});
Output:
$ node grep.js
No output? Why would that be the case? Closing grep's stdin will cause it to exit, leaving it open keeps me from seeing the output I want. All in all, how is this different from the functionality of .exec
?
I tried to link pretty closely to the documentation because I'm confident that Node is working as expected and that I've misread something that brought me here.