Bash while loop only getting the first value of a file
Posted on 2025-11-11
Occasionally, due to circumstances entirely within my control, I find myself in an odd situation. Bumping into edge cases, doing things the hard way... for whatever reason, I seem to have a knack for finding the approach with the most exotic issues. What follows, is one of these scenarios.
I have a SSH gateway that I use as a distribution point for all of my SSH public keys. Each machine gets its own key pair, and this server has all of the public keys, so that each machine can talk to the others without exchanging passwords like barbarians.
The only rub is, when I generate a new key pair, and upload the public key to
the SSH gateway, all the other servers are out of date unless I connect to them
and update their authorized_keys file. If only there were some sort of secure
protocol, one for remotely connecting to servers, that could be used to
automatically update these files...
Here's what I came up with! This is a rough adaptation, the real script has a lot more bells, whistles, and checks to prevent me from locking myself out of every server all at once.
#!/usr/bin/env bash
while read SERVER; do
echo "Updating SSH keys for $SERVER..."
ssh "$SERVER" 'cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.old'
scp ~/.ssh/authorized_keys "${SERVER}:.ssh/"
echo "Done!"
echo
done < ~/ssh_servers.txt
This code works great when I tested it manually in a bash prompt, but when I ran executed the script, it only grabbed the first value from the text file. Maddening!
I sat on this for months, and gave it another spin tonight, receiving the same results. The file was properly formatted, the script worked no matter how I fed the file/filename in, but only for the first value. I hit the search engines.
While double-checking my while loop
syntax, a note about exceptions in
the answer caught my eye. I followed the link to a very similar question about
SSH, and one of the answer explained the cause of my issue:
SSH grabbing standard input.
Turns out, I could read the file just fine - I just needed to use a different file descriptor. One that SSH wouldn't get so handsy with.
Here's the script modified to use file descriptor 7 that works great (any number between 3-9 would work):
#!/usr/bin/env bash
while read -u 7 SERVER; do
echo "Updating SSH keys for $SERVER..."
ssh "$SERVER" 'cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.old'
scp ~/.ssh/authorized_keys "${SERVER}:.ssh/"
echo "Done!"
echo
done 7< ~/ssh_servers.txt
Tags: linux networking server security terminal