Search code examples
node.jssshchild-process

Persistently run SSH commands in child_process


I am trying to start an remote ssh session to a linux machine using NodeJS. My requirements is to run multiple shell commands in the same ssh session one after another. Currently I am using simple-ssh npm package which works but my requirements says to not rely on third party tools / packages. Instead, I am suggested to use child_process for the remote ssh session.

Following is the example using simple-ssh package:

var SSH = require("simple-ssh")

var ssh = new SSH({
    host: 'remote_host',
    user: 'username',
    pass: 'password'
});

ssh.exec('pwd', {
        out: console.log.bind(console)
    })
    .exec('ls', {
        out: console.log.bind(console)
    })
    .exec('date', {
        out: console.log.bind(console)
    })
    .start();

Following is the one I tried with child_process:

  const { spawn } = require('child_process');
  const child1 = spawn('sshpass', ['-p', 'password', 'ssh', '-T', '-o', 'StrictHostKeyChecking=no', `'username'@'remote_host'`]);
       
   child1.stdin.write('password\n');

   child1.stdout.on('data', (data) => {
       console.log(`stdout: ${data}`);
   });
   child1.stderr.on('data', (data) => {
       console.error(`stderr: ${data}`);
   });
   child1.on('close', (code) => {
       console.log(`child process exited with code ${code}`);
   });


   const child2 = spawn('sshpass', ['-p', 'password', 'ssh', '-T', '-o', 'StrictHostKeyChecking=no', `'username'@'remote_host'`]);
       
   child2.stdin.write('password\n');

   child2.stdout.on('data', (data) => {
       console.log(`stdout: ${data}`);
   });
   child2.stderr.on('data', (data) => {
       console.error(`stderr: ${data}`);
   });
   child2.on('close', (code) => {
       console.log(`child process exited with code ${code}`);
   });
  
   const child3 = spawn('sshpass', ['-p', 'password', 'ssh', '-T', '-o', 'StrictHostKeyChecking=no', `'username'@'remote_host'`]);
       
   child3.stdin.write('password\n');

   child3.stdout.on('data', (data) => {
       console.log(`stdout: ${data}`);
   });
   child3.stderr.on('data', (data) => {
       console.error(`stderr: ${data}`);
   });
   child3.on('close', (code) => {
       console.log(`child process exited with code ${code}`);
   });

Also, if I run the commands in sequence, and then print the output, I get a single output for all commands (Which I don't want):

    const { spawn } = require('child_process');
    const child = spawn('sshpass', ['-p', 'password', 'ssh', '-T', '-o', 'StrictHostKeyChecking=no', `'username'@'remote_host'`]);
       
    child.stdin.write('pwd\n');

    child.stdin.write('ls -al\n');
        
    child.stdin.write('date\n');
        
    child.stdout.on('data', (data) => {
        console.log(`stdout: ${data}`);
    });

    child.stderr.on('data', (data) => {
        console.error(`stderr: ${data}`);
    });

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

My question is how can I chain the three ssh commands with child_process spawn in a persistent session and run the commands asynchronously one after another?


Solution

  • Set 'shell' option to be 'true' to runs command inside of a shell which by default is 'false'. Also you can check the node js child process spawn command documentation

    const ssh = spawn(
      "sshpass",
      [
        "-p",
        password,
        "ssh",
        "-T",
        "-o",
        "StrictHostKeyChecking=no",
        `${username}@${host}`,
      ],
      { shell: true }
    );