Scripting repetitive tasks improves the efficiency of system administration. That’s great for local machines, but what if you oversee remote servers? Can you run a local script on a remote computer? Yes!
Remote system administration usually involves making a connection to the remote computer over a secure shell connection. The SSH connection provides you with a command prompt on the remote computer. You can then go right ahead and perform whatever system maintenance is required.
Shell scripting helps by letting you wrap a sequence of commands into a script that can be run as though they were a program, combining many actions into one command line instruction.
As time goes by, you’ll tweak and improve your scripts. If you have many remote machines to administer, keeping the copy of each script on each server up to date and current is a pain, and an irksome overhead. It becomes an administrative task in itself and eats into the time savings that using scripts is supposed to deliver.
The ideal solution would let you keep your scripts on your local machine and run them on the remote computers over the SSH connection. That would give you simplified management with a centralized collection of scripts, and the same up-to-date script runs on all computers.
Bash and SSH provide a way to do just that.
Passwordless SSH Connections
The best way to do this is with passwordless connections, using SSH keys. By generating SSH keys on your local computer and sending them to each of the remote computers, you can connect to the remote computers securely and conveniently, without being prompted for a password each time.
Although they can be intimidating for first-time users, SSH keys are really not difficult. They’re easy to generate, simple to install on the remote servers, and frictionless when you use them with SSH. The only prerequisites are that the remote computers have the SSH daemon
sshd running, and that you have a user account on the remote computer.
If you’re already doing remote system administration on them, both of these requirements must already be satisfied.
To generate an SSH key pair, type:
If you have an account called “dave” on a computer called “fedora-36.local”, you could send and install your SSH public key to it with this command:
ssh-copy-id [email protected]
Now, making an SSH connection in the usual way will authenticate using the SSH keys. You’re dropped onto a command prompt on the remote server without being prompted for a password.
Running a Local Script Remotely
For these tests, our remote server is a Linux computer called “fedora-36.local.” We’ve set up SSH keys and we have tested our passwordless connection to the remote server from our local computer.
Our script is very simple. It writes a timestamp into a file called “timestamp.txt”, on the remote server. Note that the script concludes with the exit command. This is important, on some older systems it is possible for a script to run to completion, but the SSH connection is held open.
#!/bin/bash date >> timestamp.txt exit 0
Copy this text into an editor, save it as “local.sh”, and then use
chmod to make it executable.
chmod +x local.sh
On our local machine, we’ll launch the script like this:
ssh [email protected] 'bash -s' < local.sh
Here’s how this works.
- ssh [email protected]: The SSH connection we’re making to the remote machine. This uses the
sshcommand, the pre-existing user account on the remote server, and the address of the remote server.
- ‘bash -s’: This causes Bash to read commands from the standard input stream. It lets Bash read redirected or piped input.
- < local.sh: We’re redirecting the script into Bash.
When the script runs we’re returned to the command prompt of the local machine. Hopping over to our remote machine, we can use cat to look inside the “timestamp.txt” file.
We can see the timestamp of the last—and currently only—connection. Running the local script several more times adds corresponding timestamps to the remote file.
Of course, in a real-world situation, your script would do something more useful. But even our trivial example does demonstrate that a local script is being executed on a remote server.
Passing Arguments to the Script
You can pass command line arguments to the script. We’ll modify our script to expect three command line parameters. These are redirected into the “timestamp.txt” file along with the timestamp.
Save this script as “local2.sh”, and make it executable with
#!/bin/bash echo "$1 $2 $3" >> timestamp.txt date >> timestamp.txt exit 0
The command we need to use is similar to the previous example, with a few changes.
ssh [email protected] "bash -s" -- < local2.sh "How-To Geek" "Linux" "Articles"
The double-hyphen “
--” tells Bash that what follows shouldn’t be considered command line parameters for the
ssh command. The three parameters for the script follow the script name, as usual. Note that we’ve used a backslash “
” to escape the space in the “How-To Geek” parameter.
We can check with
cat that our parameters were received and handled correctly on the remote server.
Running a Section of a Script Remotely
If you have a script that needs to do some local processing in order to determine what actions might be required on the remote servers, you can add a section right into that script to perform the remote actions for you.
We can achieve this by using here documents. Here documents allow us to redirect lines from a labeled section of a script into a command. Local processing can be performed above and below the here document.
This is script “local3.sh”, which contains a here document.
#!/bin/bash # local processing can done here # remote processing is done here ssh -T [email protected] << _remote_commands # commands to be run remotely would be added here cd /home/dave/Documents # etc. # Finally, update the timestamp file echo "Script3.sh:" $(date) >> /home/dave/timestamp.txt # this is the label that marks the end of the redirection _remote_commands # more local processing can be done here exit 0
We’re using the
ssh command with the same connection details as before. We’re connecting as user “dave” on a remote server called “fedora-36.local.” We’re also using the
-T (disable pseudo-terminal allocation) option. This prevents the remote server from providing an interactive terminal for this connection.
The redirection “
<<” is followed by the name of a label. In this example, we’re using “_remote_commands.” There’s nothing special about this label, it is simply a label.
All commands that appear on the lines following the redirection are sent over the SSH connection. The redirection stops when the label is encountered. The execution of the script then continues with the line following the label.
Let’s run our mixed local/remote processing script.
As expected, we see a new entry in the “timestamp.txt” file.
Extend Your Reach
Being able to run scripts remotely—that are written, stored, and maintained locally—provides a convenient administration tool. Knowing that exactly the same version of a script runs on all of your remote servers makes management much easier.