Franck Dernoncourt
Franck Dernoncourt

Reputation: 83427

Why is this while loop not looping?

I have the following bash script deploy.sh:

#!/usr/bin/env bash

# Some useful resources:
# while read ip user pass; do : http://unix.stackexchange.com/questions/92664/how-to-deploy-programs-on-multiple-machines
# -o StrictHostKeyChecking=no: http://askubuntu.com/questions/180860/regarding-host-key-verification-failed
# -T: http://stackoverflow.com/questions/21659637/how-to-fix-sudo-no-tty-present-and-no-askpass-program-specified-error
# echo $pass |: http://stackoverflow.com/questions/11955298/use-sudo-with-password-as-parameter

while read ip user pass; do 
  echo $ip
  sshpass -p "$pass" ssh $user@$ip  -o StrictHostKeyChecking=no -T "
  echo 'yo'
  "
  echo 'done'
done < servers.txt

servers.txt contains:

53.12.45.74 my_username my_password
54.12.45.74 my_username my_password
57.12.45.74 my_username my_password
‌‌ 

From my understanding, the while read ip user pass; do […] done < servers.txt should loop over all three lines of servers.txt.

However, when I try to run it, it only performs one iteration:

ubuntu@server:~$ bash deploy.sh
53.12.45.74
yo
done
ubuntu@server:~$

Why?


If the loop is simply:

while read ip user pass; do 
      echo $ip
done < servers.txt

it does perform all three iterations:

ubuntu@server:~$ bash deploy.sh
53.12.45.74
54.12.45.74
57.12.45.74
ubuntu@server:~$

Upvotes: 3

Views: 2603

Answers (2)

alvits
alvits

Reputation: 6768

sshpass is taking control of stdin or possibly replacing it and causing while loop to lose input from redirected stdin.

To work around this issue, avoid reading from stdin.

First, load the file into an array using a while loop.

while read line; do
    entries+=("$line")
done < servers.txt

Next, use for loop to parse the lines and execute sshpass within this loop.

for line in "${entries[@]}"; do
  set $line
  ip=$1
  user=$2
  pass=$3
  echo $ip
  sshpass -p "$pass" ssh $user@$ip  -o StrictHostKeyChecking=no -T "
  echo 'yo'
  "
  echo 'done'
done

The second loop doesn't read from stdin.

But I will recommend Rany Albeg Wein answer using a separate descriptor than the current stdin.

while read ip user pass <&3; do 
  echo $ip
  sshpass -p "$pass" ssh $user@$ip  -o StrictHostKeyChecking=no -T "
  echo 'yo'
  "
  echo 'done'
done 3<servers.txt

Upvotes: 5

Timoshenko
Timoshenko

Reputation: 24

#!/usr/bin/env bash

# Some useful resources:
# while read ip user pass; do : http://unix.stackexchange.com/questions/92664/how-to-deploy-programs-on-multiple-machines
# -o StrictHostKeyChecking=no: http://askubuntu.com/questions/180860/regarding-host-key-verification-failed
# -T: http://stackoverflow.com/questions/21659637/how-to-fix-sudo-no-tty-present-and-no-askpass-program-specified-error
# echo $pass |: http://stackoverflow.com/questions/11955298/use-sudo-with-password-as-parameter

while read ip user pass; do

  if [ -n "$ip" ]; then

    echo "IP[$ip] USER[$user] PASS[$pass]";

    # dont forget to uncomment this two lines here:
    #sshpass -p "$pass" ssh $user@$ip  -o StrictHostKeyChecking=no -T "
    #echo 'yo'

    echo ""; # Just a blank line"
    echo "done.";

  else
    echo "Empty value.";
  fi

done < servers.txt

So, now it works.

Upvotes: 0

Related Questions