How to run SSH commands on multiple servers from a list

How to run SSH commands on multiple servers from a list

If you need to run the same SSH command on multiple servers, you can automate it using either a while loop or a for loop in Bash. Both methods work, but they have subtle differences that are important to understand.

Using a while read loop

The while read loop reads the server list line by line, and is safe for server names containing spaces or special characters. However, when using SSH inside the loop, you need to redirect input to avoid breaking the loop:

while read servername; do
  ssh -q "$servername" "command" < /dev/null
done < servers.txt

Example server list (servers.txt):

server1.example.com
server2.example.com
10.10.0.15
backup-node.local

Example: search for errors in a remote log:

while read servername; do
  ssh -q "$servername" "grep ERROR /var/log/syslog" < /dev/null
done < servers.txt

Using a for loop

A for loop iterates over words or lines directly. It’s shorter, but it splits words on spaces by default, which can be problematic if server names contain spaces:

for servername in $(cat servers.txt); do
  ssh -q "$servername" "command"
done

Example: search for errors in a remote log:

for servername in $(cat servers.txt); do
  ssh -q "$servername" "grep ERROR /var/log/syslog"
done

Quote handling in SSH commands

When passing a command to SSH, the remote shell interprets it. Always wrap the remote command in double quotes and escape any internal double quotes:

ssh -q "$servername" "grep \"user not found\" /var/log/auth.log"

For single quotes in the remote command, use outer double quotes:

ssh -q "$servername" "grep \"can't open file\" /var/log/app.log"

Comparison Table: while vs for loop

Feature while read loop for loop
Handles spaces in server names Yes No (splits on spaces)
Memory usage on large files Efficient (reads line by line) Less efficient (reads entire file into memory)
Input from pipes Works well Not ideal
Syntax simplicity Verbose, needs redirection for SSH Simple and short
Robustness High Lower for complex names or large lists

In general, use while read for robust scripts, and for loops for small, simple server lists. Proper quoting ensures your SSH commands run reliably on all servers.