这个 while 循环有什么问题?

这个 while 循环有什么问题?

背景

我已经创建了一个脚本来:

  • 一次读取一个 IP 列表
  • 将配置文件从本地主机复制到远程主机
  • 重启远程主机
  • 关闭当前 ssh 会话

脚本内容:

#!/bin/bash

SSHPASS="OMITTED"
FILE_TO_COPY=/opt/someConfigFile.conf
TARGET_FOLDER=/opt/

echo "Reading ip list..."
cat $1 | while read ip
do
    echo "Copying file to $ip"
    sshpass -p $SSHPASS scp -o StrictHostKeyChecking=no -o ServerAliveInterval=3 $FILE_TO_COPY root@$ip:$TARGET_FOLDER
    echo "Sending reboot command to $ip"
    sshpass -p $SSHPASS ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=3 'nohup reboot > /dev/null & exit'
    echo "Done for $ip"
done
echo "Done for all"

我的脚本从文本文件中读取条目,其中每个条目由新行分隔,例如:

192.168.XXX.XX1
192.168.XXX.XX2
192.168.XXX.XX3
192.168.XXX.XX4

当我运行此脚本时,./ConfigSender.sh /host_list.txt我可以看到以下输出:

$> ./ConfigSender.sh /host_list.txt
Rading ip list...
Copying file to 192.168.XXX.XX1
Sending reboot command to 192.168.XXX.XX1
Done for 192.168.XXX.XX1
Done for all
$>

我期望看到文件中所有条目的输出。我怀疑里面的命令以while某种方式破坏了执行。所以我编辑了脚本,只将读取的 ip 值打印到输出中:

#...
echo "Reading ip list..."
cat $1 | while read ip
do
    echo "Copying file to $ip"
done
echo "Done for all"

这是输出:

$> ./ConfigSender.sh /host_list.txt
Rading ip list...
Copying file to 192.168.XXX.XX1
Copying file to 192.168.XXX.XX2
Copying file to 192.168.XXX.XX3
Copying file to 192.168.XXX.XX4
Done for all
$>

问题

很明显,原始命令中的命令while导致了这种行为。while 循环有什么问题?我在这里遗漏了什么?

编辑

@harrymc 和 @Kamil Maciorowski 的回答都解决了我的问题,非常感谢。我决定接受 @harrymc 的回答,因为它更具描述性。

答案1

sshpass通过操纵stdin来欺骗用户,ssh使其认为它正在从交互用户那里获取密码。当您使用... | while样式循环时,循环将迭代来自的每一行stdinsshpass在第一次调用后清除。这就是为什么只有第一行被执行的原因。

有几种可能的解决方案:

  • 将 sshpass 标准输入重定向到/dev/null
  • 将整个循环体包裹在括号中以隔离 stdin( {})
  • 在循环之前分配给一个数组,这样你就不会使用 stdin
    readarray a < file
    for ip in "${a[@]}"; do
  • 循环遍历除 st​​din 之外的文件描述符
    while read -u 5 -r ip; do
    ...
    done 5<file

答案2

我做了一些测试。我认为你的台词就像

sshpass …

stdin,他们“吃”了 提供的额外 IP cat。你可以调查为什么它发生了,但知道它就足够了发生。

解决方案是给他们一些其他的输入:

</dev/null sshpass …

或者你可以像这样重建你的循环:

for ip in `cat $1`
do
done

答案3

不确定它是否能解决问题,但您没有在 ssh reboot 命令行中提供用户和主机名。

sshpass -p $SSHPASS ssh -o StrictHostKeyChecking=no -o ServerAliveInterval=3 root@$ip 'nohup reboot > /dev/null & exit'

相关内容