Published on

Shell: Execute commands on remote machine - 101 Guide

What

I have seen so many different ways on how to execute the commands in remote machine, that I thought it's worth having a centralised place for all of them explaing pros and cons.

Options

There are a lot of caveats about executing remote commands, as well as the end results you are trying to achieve. I will focus on the 2 main ones, which should over 90% of the cases.

Cases:

  • Gather information from remote machine and use it in your local script.
  • Just run the tasks on remote machine, and don't worry about output.

Few things to note in advance:

  • sshpass is used instead of ssh to avoid need to type in password (helps to achieve fully automated process)
  • StrictHostKeyChecking=no is used to avoid the need to grant access to ssh on first usage (otherwise you will be asked to type in yes when you run ssh for the first time to unknown host)
  • VM_USER, VM_IP, and VM_PASSWORD are here to simplify examples.

Set the scene

Task

Print 1-10 on the screen on new lines.

Option 1. Pass it as part of SSH

######## One Liner:
sshpass -p "$VM_PASSWORD" ssh -o StrictHostKeyChecking=no $VM_USER@$VM_IP i=0 && while [ $i -le 10 ]; do echo "It is: $i" && ((i=i+1)); done

######## Using EOF
sshpass -p "$VM_PASSWORD" ssh -o StrictHostKeyChecking=no $VM_USER@$VM_IP << EOF
i=0

while [ \$i -le 10 ]
do
  echo "It is: \$i"
  ((i=i+1))
done
EOF
Option 2. Create separate script
  1. Create new file
touch test.sh && nano test.sh && chmod +x test.sh
  1. Update test.sh to contain code you want to execute
while [ $i -le 10 ]
do
  echo "It is: $i"
  ((i=i+1))
done
  1. Send the file to host machine and execute it.
sshpass -p "$VM_PASSWORD" rsync -av test.sh $VM_USER@$VM_IP:~/test.sh
i=0
sshpass -p "$VM_PASSWORD" ssh -o StrictHostKeyChecking=no $VM_USER@$VM_IP << EOF
export i=$i # Here you are setting remote variable 'i' to the value of internal $i, or 0 if that is not set
./test.sh

####### Pros/Cons

TypeProsCons
One liner pass it aspart of SSHShort
Works well for 1 command
Gets extremely complicated if you are trying to do more then 1 command
Pass it as part of SSH using EOFMuch more readable then one liner
No need to use && constantly
You need to be aware of escaping $ signs (use $) to avoid using your environment values
Impossible to test without executing parent script once your code gets complicated
Create file, send the file to VM and execute itSingle responsibility script
You stick with proper development experience
Can test in remote at any time
When you get tens of 'single responsibiity' scripts, you end-up flooding your repository, so it gets hard to manage your scripts

Conclusions

As everything in this word, there is no best or worst, and it depends on your situation. From my past experience I would definitely strongly suggest sending separate scripts to your remote machine and executing them with idea of single responsibility scripts.

But have a read again at pros and cons, decide which one to go with, and stick with it!

Good luck bashing!