web-dev-qa-db-ja.com

このwhileループの何が問題になっていますか?

背景

次のスクリプトを作成しました。

  • 一度に1つの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と@KamilMaciorowskiの両方の回答が私の問題を解決しています、どうもありがとう。 @harrymcの回答はより説明的であるため、受け入れることにしました。

3
raidensan

sshpassは、stdinを操作してsshをだまし、対話型ユーザーからパスワードを取得していると思い込ませることで機能します。 ... | whileスタイルのループを使用すると、ループはstdinからのすべての行に対して繰り返され、最初の呼び出し後にsshpassが消去されます。そのため、最初の行だけが実行されます。

いくつかの解決策が可能です:

  • 標準入力を/dev/nullにsshpassするためにリダイレクトします
  • ループ本体全体を中括弧で囲んで、stdinを分離します({}
  • Stdinを使用しないように、ループの前に配列に割り当てます
    readarray a < file
    for ip in "${a[@]}"; do
  • Stdin以外のファイル記述子をループする
    while read -u 5 -r ip; do
    ...
    done 5<file
3
harrymc

私はいくつかのテストを行いました。私はあなたのラインが好きだと思います

sshpass …

stdinを読むと、catによって提供される追加のIPを「食べる」。あなたは調査することができますなぜそれが起こるがそれが起こることを知るのに十分ですする起こる。

解決策は、他の入力を与えることです。

</dev/null sshpass …

または、次のようにループを再構築できます。

for ip in `cat $1`
do
 …
done
2

問題が解決するかどうかはわかりませんが、sshrebootコマンドラインでユーザーとホスト名を指定していません。

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

0
vera