for、while を使用してファイルを読み取る - 動作

for、while を使用してファイルを読み取る - 動作

以下のシナリオを考えてみましょう

2 つの仮想マシン - 192.168.229.131、192.168.229.132

両方のVMの/etc/hostsファイルにはIPが192.168.229.151と192.168.229.152として記録されています。

上で述べたように、VM は約 50 個あるとします。ただし、現時点では上記の 2 つだけを検討しています。

2つのVMのIPをserverという名前のファイルに保存しました

#cat server
192.168.229.131
192.168.229.132

以下はスクリプトです

#!/bin/bash
cat server | while read line
do
/usr/bin/sshpass -e ssh -t -q -o StrictHostKeyChecking=no root@$line << EOF
echo successfully logged in $line
MYIP=$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p')
for i in 151 152
do
echo 192.168.229.\$i >> errips
done
for data in `cat errips`
do
echo data currently has $data
grep $data /etc/hosts
if [ $? -eq 0 ]
then
sed -i "s/$data/$MYIP/g" /etc/hosts
echo "completed"
unset MYIP
rm -rf errips
exit 0
fi
done
EOF
done

以下は出力です

root@master:~# ./script
cat: errips: No such file or directory
successfully logged in 192.168.229.131
cat: errips: No such file or directory
successfully logged in 192.168.229.132

サーバーにログインした後の for ループが、ログインする前に実行されるのはなぜですか?

「for」の代わりに以下を使ってみました

cat errips |while read line
echo line currently has $line

この場合、その行は、リモートでログインしたサーバーの errips ファイルから読み取る必要があるにもかかわらず、localhost のサーバー ファイルから IP を取得していることがわかりました。

出力は

line currently has 192.168.229.131
line currently has 192.168.229.132

私は、ファイル「errips」の値を読み取り、出力が以下のようなものになることを期待していました。

line currently has 192.168.229.151
line currently has 192.168.229.151

さて、以下のコマンドを試してみました

cat errips |while read data
echo data currently has $data

この場合、値データの出力は空でした

data currently has 
data currently has

リモート サーバーのファイル「errips」を 1 行ずつ読み取り、/etc/hosts でその行を grep し、if ループを実行して間違った IP を正しい IP に置き換えるにはどうすればよいでしょうか。

答え1

ヒアドキュメントの制限文字列を一重引用符で囲む必要があります。そうしないと、パラメータ置換が有効になります。これは動作するはずです:

#!/bin/bash
cat server | while read line
do
  /usr/bin/sshpass -e ssh -t -q -o StrictHostKeyChecking=no root@$line <<'EOF'
  echo successfully logged in $line
  MYIP=$(ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p')
  for i in 151 152
  do
    echo 192.168.229.$i >> errips
  done
  for data in `cat errips`
  do
    echo data currently has $data
    grep $data /etc/hosts
    if [ $? -eq 0 ]
    then
      sed -i "s/$data/$MYIP/g" /etc/hosts
      echo "completed"
      unset MYIP
      rm -rf errips
      exit 0
    fi
  done
EOF
done

EOF を囲む一重引用符に注意してください。さらに詳しく説明するには、次の例を試してください。

/usr/bin/sshpass -e ssh -t -q -o StrictHostKeyChecking=no root@<your_ip> 'k=1; echo $k'
/usr/bin/sshpass -e ssh -t -q -o StrictHostKeyChecking=no root@<your_ip> "k=1; echo $k"
/usr/bin/sshpass -e ssh -t -q -o StrictHostKeyChecking=no root@<your_ip> "k=1; echo \$k"

関連情報