題 這個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 以某種方式打破了執行。所以我編輯了我的腳本,只是將read 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的回答,因為它更具描述性。


4
2017-08-02 11:27


起源




答案:


sshpass 通過操縱來工作 stdin 愚弄 ssh 認為它是從交互式用戶獲取密碼。當你使用 ... | while 樣式循環,循環迭代來自的每一行 stdin, 哪一個 sshpass 第一次通話後消失。這就是為什麼只有第一行被執行。

有幾種解決方案可行:

  • 重定向sshpass標準輸入 /dev/null
  • 將整個循環體包裹成支架以隔離stdin({}
  • 在循環之前分配給數組,這樣就不會使用stdin
    readarray a < file
    for ip in "${a[@]}"; do
  • 循環除stdin之外的文件描述符
    while read -u 5 -r ip; do
    ...
    done 5<file

3
2017-08-02 12:09





我做了一些測試。我覺得你的台詞就好

sshpass …

stdin,他們“吃”了提供的額外IP cat。你可以調查一下 為什麼 它發生了,但它足以知道它  發生。

解決方案是給他們一些其他的輸入:

</dev/null sshpass …

或者你可以像這樣重建你的循環:

for ip in `cat $1`
do
 …
done

2
2017-08-02 12:05





不確定它是否會解決問題,但您沒有在ssh reboot命令行中提供用戶名和主機名。

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


0
2017-08-02 11:48