How do I run a local bash script on remote machines via ssh?

Solution 1:

You can pass a script and have it execute ephemerally by piping it in and executing a shell.

e.g.

echo "ls -l; echo 'Hello World'" | ssh me@myserver /bin/bash

Naturally, the "ls -l; echo 'Hello World'" part could be replaced with a bash script stored in a file on the local machine.

e.g.

cat script.sh | ssh me@myserver /bin/bash

Cheers!

Solution 2:

There are several ways to do it.

1:

ssh user@remote_server 'bash -s' < localfile

2:

cat localfile  | ssh user@remote_server

3:

ssh user@remote_server "$(< localfile)"

number 3 is my prefered way, it allows interactive commands e.g. su -S service nginx restart

(#1 will consume the rest of the script as input for the password question when you use su -S.)


Solution 3:

I would recommend python's Fabric for this purpose:

#!/usr/bin/python
# ~/fabfile.py

from fabric_api import *

env.hosts = ['host1', 'host2']
def deploy_script():
    put('your_script.sh', 'your_script.sh', mode=0755)
    sudo('./your_script.sh')

# from shell
$ fab deploy_script

You should be able to use the above to get started. Consult Fabric's excellent documentation to do the rest. As an addendum, it's totally possible to write your script wholly within Fabric -- no copying needed, however it should be noted that to change the script on all machines, you would only need to edit the local copy and redeploy. Furthermore, with a little more than basic usage of the API, you can modify the script based on which host it is currently running on and/or other variables. It's a sort of pythonic Expect.


Solution 4:

This is exactly what Ansible is used for. There is no agent, you just have to create a text file called:

/etc/ansible/hosts

with content that looks something like:

[webhosts]
web[1-8]

This would specify that machines "web1, web2...web8" are in the group "webhosts". Then you can do things like:

ansible webhosts -m service -a "name=apache2 state=restarted" --sudo

to restart the apache2 service on all your machines, using sudo.

You can do on the fly commands like:

ansible webhosts -m shell -a "df -h"

or you can run a local script on the remote machine:

ansible webhosts -m script -a "./script.sh"

or you can create a playbook (look up the documentation for details) with a complete configuration that you want your servers to conform to and deploy it with:

ansible-playbook webplaybook.yml

Basically you can start using it as a command line tool for running commands on multiple servers and expand its usage out into a complete configuration tool as you see fit.


Solution 5:

As explained in this answer you can use heredoc :

ssh user@host <<'ENDSSH'
#commands to run on remote host
ENDSSH

You have to be careful with heredoc, because it just sends text, but it doesn't really wait for the response. That means it will not wait for your commands to be executed.