Ssh in for loop

I have a script to retrieve information from servers. However, some servers use password authentication while others use public key authentication with port 2222. Is there a way to SSH into servers using both password and public key authentication?

Here's my sample scripts

for i in $(cat /opt/servers); do
        if nmap -sP "$i" |grep -i "Host is up" >/dev/null; then
                 
                CON=$i
                STATUS='LIVE'
				
              `ssh -o StrictHostKeyChecking=no -q -p 2222 $i 'cat /sys/class/net/eth0/speed /sys/class/net/eth0/duplex; ifconfig eth0 |grep errors; dmidecode |grep -i "product name:" |tail -1 ; uptime;'> /tmp/DATA`

              `sshpass -p mypassword q ssh -o StrictHostKeyChecking=no  $i -l username 'cat /sys/class/net/enp1s0/speed /sys/class/net/enp1s0/duplex ; ifconfig enp1s0 |grep errors ; dmidecode |grep -i "Product Name:"|tail -1 ; uptime' > /tmp/DATA`
               printf "%-5s | %-6s | %-6s | %-10s | %-18s | %-15s\n" "${CON}" "${STATUS}"
          
        else
                # Else display terminal is offline
                CON=`echo "$i"`
                STATUS='----- Terminal down -----'
                printf "%-5s | %-40s\n" "${CON}" "${STATUS}"

        fi
done

you might be able to do that with sshpass - please google it the forum does not seem to allow links at this time

@kraigpena, yes it is possible using sshpass I did try.. thanks for your help

1 Like

You might want to investigate the BatchMode option (-o) which will prevent ssh from asking for a password.

This is germane when you want to force something to use keys or credentials. -- This helps make sure that the code path only had to work with one and not prefer one and fall back to the other. E.g. don't prompt for a password when the key didn't work. Instead having your calling code detect this and use a different code path to support passwords.

3 Likes

Thank you for "pinging" the host before trying to SSH into it. Lots of folks forget this bit. If you don't check, and it's down, the SSH takes longer to time out, or it hangs completely.

I have noticed that reading a file for the hostnames and performing an ssh in the loop can cause the master script to forget where it is in the file and then it does not loop properly through all of the hosts. Not exactly sure of the details as to why.

If you encounter this problem, read all the hostnames from the file into an array and then loop over that.

Also, depending on your input file, if you have comments or blank lines, nmap will try to ping those. Not a big deal, as it will fail, but it clogs up your output with things you don't need and takes longer (depending on how many hosts you have).
Consider grepping out comments and blank lines.
$0.02

Pinging is a good idea if the environment supports it. I've been in too many environments that think it's a good idea to filter ICMP.

In these cases, the ssh ConnectTimeout option (-o) to some value that's two or three times the average is prudent.

Yes, it will delay, but it won't delay indefinitely.

1 Like

Perhaps you mean a while loop reading from stdin? Then ssh might fill a buffer from stdin, stealing data from the input.
Workarounds:

  1. use another file descriptor in the while-read
  2. use ssh -n
  3. redirect ssh's stdin.

A for $(cat ...) loop immediately reads the complete file into a list, and is not affected by the ssh behavior.

A for $(cat ...) loop splits at "whitespace" i.e. any contiguous space including tabs and newlines. To grep out comments, both
for $(grep '^[^#]' ...) and
for $(grep -v '^#' ...)
work here.

1 Like