I regularly need to update some Ubuntu 12.04 (Precise Pangolin) servers (Rackspace).

What I do now is:

  • Copy a file to a server using SCP
  • Log on to the server using SSH
  • Stop Tomcat
  • Do some copying and moving of the uploaded file
  • Start Tomcat

Repeat the exact same process with the same file on the second server (12 servers now and the number is growing).

Is it possible to write a script that loops through a list of servers and does all this for me?

How would I go about it? Preferably the solution would not necesitate the install of any stuff. The majority within the company works on MacBooks, but Windows VM's are abundant.

Ideally servers to be updated can simply be added/removed to change the list of servers. However, any solution that saves me the time of doing the same thing +12 times is very much appreciated :)

  • 1
    Would clusterssh do what you want? – ericx Sep 8 '15 at 15:20

There are several solutions for this - do you want to keep manual control of the steps and simply run through them simultaneously? The look at CSSH (if you're coming from a Linux system) or SuperPutty (if you're coming from a Windows system). If you simply want to automate everything, look at Expect.

|improve this answer|||||
  • I really love those tools! However, this task will not only be done by me so I prefer a solution that does not involve configuring anything. That is not tos say that I really really appreciate the tools you mentioned, they are pretty cool :) – Henrov Sep 8 '15 at 14:30
  • At some level, everything requires some configuration. You can reduce the configuration required, but it'll be rare indeed when you can completely eliminate all need for configuration. – John Sep 8 '15 at 14:32
  • I guess you are right in that. I was hoping there would be a way to simply script it :| hus avoiding any configuration – Henrov Sep 8 '15 at 14:36
  • That's what Expect does for you, but even with Expect, there will be some configuration required. – John Sep 8 '15 at 14:38


Depending on the script you could run all through ssh:

for server in s1 s2 s3; do
    ssh $server "command one; command two; ..."

Or split it into multiple calls:

for server in s1 s2 s3; do
    ssh $server command one
    ssh $server command two

Feel free to add this to your answer, just passing by ..

|improve this answer|||||
  • I considered that option as well, but because the asker specifically mentioned running a script I thought I'd target transferring a script and running it. The asker also has a handful of commands to run and transferring a script is more maintainable. However this route is great if you only need one or two commands, I normally leave a script like this on my management server that takes the command in as an argument to make life easy. – Centimane Sep 9 '15 at 10:08
  • Following your suggestion I came up with this (and it works :) HOSTS='server 1 server 2' for h in $HOSTS; do scp file1 file2 $h:$target_dir done – Henrov Sep 10 '15 at 12:37

Do yourself a favor and check out Ansible. It sounds like it's exactly what you need. It uses SSH and scales up easily, all you have to do is add the servers to the list as needed. Learning to make a playbook will take you an afternoon and will save you countless hours in the future.

|improve this answer|||||

As others have mentioned there are tools designed for managing multiple machines, but for a purely bash solution you can write a for loop and execute commands through ssh on a handful of nodes.

Assuming host1 and host2 are the hostnames of ndoes you want this to happen from:

for node in host1 host2; do
    scp /tmp/script.sh user@$node:/tmp/script.sh
    if [[ "$?" == "0" ]];then #checks that last command didn't return an error
        ssh -oBatchMode=yes user@$node /tmp/script.sh

If you're going to use this solution I recommend configuring ssh keys so that you don't have to input the password each time. The BatchMode option will cause the script to skip rather than wait for input, you can decide if that's preferable.

|improve this answer|||||
  • 2
    You probably want to make the second command (that executes the script) conditional on the first. Otherwise, you're at risk of running code because you couldn't overwrite it. – Toby Speight Sep 8 '15 at 15:42
  • @TobySpeight A good call, I'll edit my answer – Centimane Sep 8 '15 at 16:41
  • 1
    In script.sh, I would make the last line rm -f /tmp/script.sh so that it removes itself upon completion—just keeps things tidy and prevents it from being run again, locally. – forquare Sep 8 '15 at 17:22
  • 1
    @forquare I agree, a good bet is to remove the script when done, but it's still a good idea to ensure someone couldn't place a file /tmp/script.sh with the anticipation that you would run it for them. Otherwise they could make sure you didn't have write permission, but did have read/execute on the script and get you to do malicious things. Of course script.sh was just a dummy name I used for my example, but still a good practice. – Centimane Sep 8 '15 at 18:12
  • @Dave completely agree! – forquare Sep 8 '15 at 20:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.