6

I'm trying to deploy from GitHub using I want to execute more than one command, in order of the array. The code I'm using now is included below.

async.series([
...
// Deploy from GitHub
function (callback) {
    // Console shizzle:
    console.log('');
    console.log('Deploying...'.red.bold);
    console.log();
    console.log();

    var deployFunctions = [
        {
            command: 'cd ' + envOptions.folder + ' && pwd',
            log: false
        },
        {
            command: 'pwd'
        },
        {
            command: 'su ' + envOptions.user,
            log: false
        },
        {
            command: 'git pull'
        },
        {
            command: 'chmod 0777 * -R',
            log: false
        }
    ];
    async.eachSeries(deployFunctions, function (item, callback) {
        deployment.ssh2.exec(item.command, function (err, stream) {
            deployment.logExec(item);
            stream.on('data', function (data, extended) {
                console.log(data.toString().trim());
                console.log();
            });
            function done() {
                callback(err);
            }

            stream.on('exit', done);
            stream.on('end', done);
        });
    }, function () {
        callback();
    });
},
...);

But, after I cd'ed to the right directory, it forgets where it was and starts all over again.

$ cd /some/folder && pwd
/some/folder

$ pwd
/root
5
  • But that doesn't describe how to execute more commands after each other, does it? Commented Jan 3, 2014 at 15:36
  • 3
    The commands are run sequentially, and probably each in a different shell instance, which means that any changes in the environment (like the current working directory) aren't 'sticky'. Perhaps use .shell instead of .exec, although you may have to rewrite how you execute commands (or prefix each command with cd ... &&). Commented Jan 3, 2014 at 15:38
  • 1
    How would you suggest to work with .shell? I can't seem to find much examples using node-ssh2 module, so it's quite hard to get a hold of how it should be used (properly). Commented Jan 3, 2014 at 15:41
  • 1
    Here are some ideas: gist (not exceptionally beautiful I'm afraid). You may want to move the async loop to inside the .shell handler. Commented Jan 3, 2014 at 16:00
  • One solution would be to extend what you have with 'cd ' + envOptions.folder + ' && pwd' to build up a string that has all commands you want to execute. Recall that you can either separate cmds with ; , && (as you know), and ||. Good luck. Commented Jan 3, 2014 at 16:01

4 Answers 4

6

@robertklep is correct about why your cd doesn't persist. Each command invokes a distinct shell instance which starts in its initial state. You could prefix each command with cd /home/jansenstok/domains/alcoholtesterwinkel.com/public_html/ && as a quick fix, but really you are setting yourself up for pain. What you want is a shell script with all the power of multiple lines as opposed to a list of individual disconnected commands.

Look at using ssh2's sftp function to transfer a complete shell script to the remote machine as step 1, execute it via exec (/bin/bash /tmp/your_deploy_script.sh) as step 2, and then delete the script as step 3.

Sign up to request clarification or add additional context in comments.

2 Comments

@Peter, this is a nice approach. in btw, how can we read the multiple command's output in the original terminal. one can put echo statements between each command as a delimiter, but i am looking for a better approach..
By default if you run a bash script, the output of all commands will be read (stdout and stderr). You don't need to do anything special to get it.
2

I know this is a super old question, but I ran into this problem while trying to manage an ACE through my Node server. The answer didn't work for me, but several searches later led me to a wrapper that worked really well for me. Just wanted to share here because this was the top link in my Google search. It's called ssh2shell and can be found here: https://www.npmjs.com/package/ssh2shell

It's very simple to use, just pass an array of commands and they run one by one waiting for each command to complete before moving on to the next.

Comments

1

A practical example:

  const client = new Client();
  const cmds = [
    'ls -lah \n',
    'cd /mnt \n',
    'pwd \n',
    'ls -lah \n',
    'exit \n',
  ];
  client.on('ready', () => {
      console.log('Client :: ready');
      client.shell((err, stream) => {
        stream.on('close', (code) => {
          console.log('stream :: close\n', { code });
        }).on('data', (myData) => {
          console.log('stream :: data\n', myData.toString());
        }).on('exit', (code) => {
          console.log('stream :: exit\n', { code });
          client.end();
        }).on('error', (e) => {
          console.log('stream :: error\n', { e });
          rej(e);
        });
        for (let i = 0; i < cmds.length; i += 1) {
          const cmd = cmds[i];
          stream.write(`${cmd}`);
        }
      });
    }).connect({
    host: '127.0.0.1',
    port: 22,
    username: 'root',
    password: 'root',
  });

all the examples in the doc use stream.end() which caused the creation of a new session instead of using the current one.

Comments

0

You cooldn't use "shell" on your program because "Shell" command invokes a new terminal on the system and does your jop. You need to use "exec" command without not emitting "exit" . Default "exec" command emits "exit" command after the command which you gave has been executed.

1 Comment

Can you please explain how exactly can we use exec() without it emitting the exit event and closing the connection?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.