5

I'm trying to test the ssh connection of a set of hosts using a corresponding set of test user accounts.

ie: testuser1 test ssh connection to server1, testuser2 test ssh connection to server2, testuser3 test ssh connection to server3 ect.

Each test user is logging in using a private key: ssh -i ~/keys/testuser1key testuser1@server1

However, I'm running into an issue when putting this information into a variable. Here is what I have for a script so far:

for host in $(cat hosts)
do
   if
      ssh -i $host 'true' exit
   then
      echo "SSH connection for $host ok"
   else
      echo "SSH connection for $host failed"
   fi
done
$SHELL

The host file looks like this:

~/keys/testuser1key testuser1@server1
~/keys/testuser2key testuser2@server2
~/keys/testuser3key testuser3@server3
...

I am getting errors such as could not resolve hostname true

I think the space in the host file are what's breaking the script. I've used a similar script no issue when running my user account and no "-i" ssh flag. (ssh myuseraccount@testserver1)

Any help or suggestions on a better way to do this is appreciated!

2
  • Could you use Ansible instead of bash? Much easier with Ansible. – Adam J Richardson Jul 16 at 7:38
  • @AdamJRichardson this is good for learning bash – annahri Jul 18 at 11:07
7

I'd suggest using a while read loop so that you can assign whitespace-separated tokens to individual variables, rather than relying on the implicit split+glob behavior of $(cat hosts)

The only tricky bit is that read reads from standard input by default - and so does ssh. So you either need to pass the -n flag to tell ssh to read from /dev/null:

while read -r identityfile host; do
  if ssh -n -i "$identityfile" "$host" true
  then
    echo "SSH connection for $host ok"
  else
    echo "SSH connection for $host failed"
  fi
done < hosts

or tell read to read from a different file descriptor:

while read -u3 -r identityfile host; do
  if ssh -i "$identityfile" "$host" true
  then
    echo "SSH connection for $host ok"
  else
    echo "SSH connection for $host failed"
  fi
done 3< hosts

Note: you've made things somewhat difficult by using ~ rather than $HOME for example to prefix the identity file portion of your hosts file. Quoting "$identityfile" prevents tilde expansion by the shell; however leaving it unquoted (as $identityfile) is dangerous because it permits word splitting and filename generation1. It seems that at least the OpenSSH implementation of ssh expands ~ itself, but if your ssh implementation doesn't, then extra processing would be required to handle it properly.

1 in this context it is filename generation (globbing) that is the primary concern, since if the name contains whitespace the whole approach is flawed.

3
  • man ssh_config, "for user configurations, shell-like ‘~’ references to user home directories" – roaima Jul 15 at 21:22
  • 1
    @roaima I was thinking of using "${identityfile/#~/$HOME}", but tbh I think I'd do something KISS like replacing < hosts with < <(sed 's/^~/$HOME/' hosts) – steeldriver Jul 15 at 22:04
  • Even better (and I've learned today that you can anchor to start-of-string with # in a substitution too) – roaima Jul 16 at 6:16

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.