How to send input to child process created with spawn? nodejs

Viewed 8255

I'm running Windows 10, and I have a program, let's call it program, that can be run from the command line. When run, it responds to commands the user enters. The user enters a command, presses the return key, and the program prints a response. I did not make this program and do not have the source, so I cannot modify it.

I want to run this program from within Node.js, and have my Node.js program act as the user, sending it commands and getting the responses. I spawn my program like this:

var spawn = require('child_process').spawn;
var child = spawn('program');

child.stdout.on('data', function(data) {
    console.log(`stdout: ${data}`);
});

Then I attempt to send it a command, for example, help.

child.stdin.write("help\n");

And nothing happens. If I manually run the program, type help, and press the return key, I get output. I want Node.js to run the program, send it input, and receive the output exactly as a human user would. I assumed that stdin.write() would send the program a command as if the user typed it in the console. However, as the program does not respond, I assume this is not the case. How can I send the program input?

I've seen many similar questions, but unfortunately the solutions their authors report as "working" did not work for me.

3 Answers

Here is what worked for me. I have used child_process exec to create a child process. Inside this child process Promise, I am handling the i/o part of the cmd given as parameter. Its' not perfect, but its working.

Sample function call where you dont need any human input.

executeCLI("cat ~/index.html");

Sample function call where you interact with aws cli. Here

executeCLI("aws configure --profile dev")

Code for custom executeCLI function.

var { exec } = require('child_process');
async function executeCLI(cmd) {
  console.log("About to execute this: ", cmd);
  var child = exec(cmd);
  return new Promise((resolve, reject) => {
    child.stdout.on('data', (data) => {
      console.log(`${data}`);
      process.stdin.pipe(child.stdin);
    });

    child.on('close', function (err, data) {
      if (err) {
        console.log("Error executing cmd: ", err);
        reject(err);
      } else {
        //   console.log("data:", data)
        resolve(data);
      }
    });
  });
}

This worked for me, when running from Win10 CMD or Git Bash:

console.log('Running child process...');
const spawn = require('child_process').spawn;
const child = spawn('node');
// Also worked, from Git Bash:
//const child = spawn('cat');

child.stdout.on('data', (data) => {
    console.log(`stdout: "${data}"`);
});

child.stdin.write("console.log('Hello!');\n");
child.stdin.end(); // EOF

child.on('close', (code) => {
    console.log(`Child process exited with code ${code}.`);
});

Result:

D:\Martin\dev\node>node test11.js
Running child process...
stdout: "Hello!
"
Child process exited with code 0.

I also tried running aws configure like this, first it didn't work because I sent only a single line. But when sending four lines for the expected four input values, it worked.

Maybe your program expects special properties for stdin, like being a real terminal, and therefore doesn't take your input?
Or did you forget to send the EOF using child.stdin.end();? (If you remove that call from my example, the child waits for input forever.)

Extract the user input code from browser and save that code into a file on your system using fs module. Let that file be 'program.cpp' and save the user data input in a text file.

As we can compile our c++ code on our terminal using g++ similarly we will be using child_process to access our system terminal and run user's code.

execFile can be used for executing our program

var { execFile } = require('child_process');

execFile("g++", ['program.cpp'], (err, stdout, stderr) => {
    if (err) {
        console.log("compilation error: ",err);
    } else{
        execFile ('./a.out' ,['<', 'input.txt'], {shell: true}, (err, stdout, stderr) => {
            console.log("output: ", stdout);         
        })
    }
})

In this code we simply require the child_process and uses its execFile function.

  • First we compile the code present in program.cpp, which creates a default a.out as output file
  • Then we pass the a.out file with input that is present in input.txt

Hence you can view the generated output in your terminal and pass that back to the user.

for more details you can check: Child Processes

Related