【问题标题】:Why is this while loop not looping?为什么这个while循环不循环?
【发布时间】:2016-04-23 10:14:29
【问题描述】:

我有以下 bash 脚本 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 包含:

53.12.45.74 my_username my_password
54.12.45.74 my_username my_password
57.12.45.74 my_username my_password
‌‌ 

据我了解,while read ip user pass; do […] done &lt; servers.txt 应该遍历servers.txt 的所有三行。

但是,当我尝试运行它时,它只执行一次迭代:

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

为什么?


如果循环很简单:

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

它确实执行了所有三个迭代:

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

【问题讨论】:

  • 那是完整的剧本还是真实剧本的代表?如果是代表,你可能忽略了 while 循环中的 break 语句。
  • @alvits 完整脚本,我只是更改了 IP、用户名和密码。
  • 看来sshpass 正在控制stdin 或可能替换它并导致while 循环丢失来自重定向stdin 的输入。尝试在像(sshpass -p "$pass" ssh $user@$ip -o StrictHostKeyChecking=no -T " echo $pass | sudo -S sudo /etc/init.d/ganglia-monitor restart ") 这样的子shell 中运行sshpass,看看问题是否得到解决。
  • @alvits:我认为这是正确的。考虑将其发布为答案。

标签: bash loops


【解决方案1】:

sshpass 正在控制stdin 或可能替换它并导致while 循环丢失来自重定向的stdin 的输入。

要解决此问题,请避免从标准输入读取。

首先,使用while 循环将文件加载到数组中。

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

接下来,使用for循环解析行并在这个循环中执行sshpass

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

第二个循环不是从stdin读取的。

但我会推荐 Rany Albeg Wein answer 使用与当前 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

【讨论】:

  • 谢谢,我刚试过,问题依旧:它只执行一次迭代:(
  • @FrankDernoncourt 我在这里回答了类似的问题stackoverflow.com/a/36584819/5649859
  • @RanyAlbegWein 感谢您的链接,抱歉我在谷歌搜索时错过了它。
【解决方案2】:
#!/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

所以,现在可以了。

【讨论】:

  • 谢谢,我刚试过,问题依旧:它只执行一次迭代:(
猜你喜欢
  • 2018-03-17
  • 1970-01-01
  • 1970-01-01
  • 2016-07-27
  • 1970-01-01
  • 2016-08-22
  • 1970-01-01
  • 2012-01-17
  • 1970-01-01
相关资源
最近更新 更多