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.