変数をループする


16

約20の異なるサーバーでrsyncを使用してファイルを更新するbashスクリプトを書いています。

rsyncの部分を把握しました。私が問題を抱えているのは、変数のリストを調べることです。

これまでの私のスクリプトは次のようになります。

#!/bin/bash
SERVER1="192.xxx.xxx.2"
SERVER2="192.xxx.xxx.3"
SERVER3="192.xxx.xxx.4"
SERVER4="192.xxx.xxx.5"
SERVER5="192.xxx.xxx.6"
SERVER6="192.xxx.xxx.7"

for ((i=1; i<7; i++))
do
    echo [Server IP Address]
done

どこ [Server IP Address]関連する変数の値はべきか。したがって、i = 1の場合、$ SERVER1の値をエコーする必要があります。

これを含むいくつかの反復を試しました

echo "$SERVER$i"    # printed the value of i
echo "SERVER$i"     # printer "SERVER" plus the value of i ex: SERVER 1 where i = 1
echo $("SERVER$i")  # produced an error SERVER1: command not found where i = 1
echo $$SERVER$i     # printed a four digit number followed by "SERVER" plus the value of i
echo \$$SERVER$i    # printed "$" plus the value of i

スクリプトを作成してから長い時間が経ちましたので、何か不足していることがわかります。さらに、過去11年間使用してきたC#を使用してできることをミックスしていると確信しています。

私がやろうとしていることも可能ですか?または、これらの値を配列に入れて配列をループする必要がありますか?実稼働IPアドレスとロケーション名についても同じことが必要です。

これはすべて、リモートサーバー上のファイルを同期するために使用するコードブロックを繰り返す必要がないようにするための努力です。


すべての回答とコメントをありがとう。私はおそらくアレイアプローチを採用します。
ポール・ストーナー

回答:


33

配列を使用します。

#! /bin/bash
servers=( 192.xxx.xxx.2 192.xxx.xxx.3
          192.xxx.xxx.4 192.xxx.xxx.5
          192.xxx.xxx.6 192.xxx.xxx.7
)

for server in "${servers[@]}" ; do
    echo "$server"
done

6
+1; また、配列要素の前/後/間に任意の空白を配置できるため、OPのように(必要に応じて)1行に1つの要素を配置できます。
-ruakh

@ruakh:ありがとう、何ができるかを示すために更新されました。
チョロバ

28

他の答えが指摘するように、これを行うには配列が最も便利な方法です。ただし、完全を期すために、あなたが求めているのは間接的な拡張です。次のように書き換えると、サンプルもこのメソッドを使用して機能します。

#!/bin/bash
SERVER1="192.xxx.xxx.2"
SERVER2="192.xxx.xxx.3"
SERVER3="192.xxx.xxx.4"
SERVER4="192.xxx.xxx.5"
SERVER5="192.xxx.xxx.6"
SERVER6="192.xxx.xxx.7"

for ((i=1; i<7; i++))
do
    servervar="SERVER$i"
    echo "${!servervar}"
done

IPアドレスのリストをforループに入れるだけで問題ない場合は、必要に応じてブレース拡張を繰り返して使用することも検討してください。

#!/bin/bash

for server in \
192.xxx.xxx.{2..7} \
192.yyy.yyy.{42..50} \
192.zzz.zzz.254
do
    echo "$server"
done

ただし、(おそらくブレース展開された)リストを再利用する必要がある場合は、リストを使用して配列を初期化する方法があります。

#!/bin/bash

servers=(
192.xxx.xxx.{2..7} 
192.yyy.yyy.{42..50}
192.zzz.zzz.254 )

for server in "${servers[@]}"
do
    echo "$server"
done

14

私はおそらく配列の回答の1つを使用して自分自身で答えますが、名前を直接ループすることは可能であることを指摘したいと思います。できるよ

for name in "${!SERVER*}"; do
    echo "${!name}"
done

または、4.3以降では、次を使用できますnameref

declare -n name
for name in "${!SERVER*}"; do
    echo "$name"
done

帽子の先端ilkkachu <4.3ソリューションのため。


2
間接展開(${!var})はBashの古いバージョンでも機能しますfoo1=aa; foo2=bbb; foox=cccc; for p in "${!foo@}"; do echo "$p = ${!p}"; done
。– ilkkachu

@ilkkachu支援してくれてありがとう。回答を更新しました。
小次郎

6

配列を使用する必要があると言った人は誰でも正しいですが、学術的な演習として、数字で終わる個別の変数(SERVER1、SERVER2など)でそれを行うことに決めた場合、これがあなたのやり方ですそれ:

for ((i=1; i<7; i++))
do
    eval echo \"\$SERVER$i\"
done

eval安全に使用するのは難しいです。はい、これは機能しますが、bashの間接的な展開は一般に優れた方法です。
ピーター

習慣。bashであってもシェルスクリプトを書き始めたとき、間接的な拡張はありませんでした。適切に脱出する方法を理解していれば、「評価」は完全に安全です。それでも、間接的な拡張の方が良いことに同意します...しかし、古い方法はまだ機能します。とにかくこの場合も私はしません。配列を使用します!
ビームデイビス

この場合は、あなたがそうした後、二重引用符をエスケープしていなかったという通知がeval行われ、あなたが持っているecho $SERVER1、ではありませんecho "$SERVER1"。はい、安全に使用できますが、非常に簡単に安全でないか、意図しない方法で使用できます!
ピーター

サーバー名にはスペースが含まれないため、この場合はとにかく重要ではありませんでした...しかし、あなたは正しい、二重引用符はエスケープする必要があります。答えが修正されました!
ビームデイビス

右、二重引用符を完全に削除する(それらが何かを保護しているという誤解を招く印象を回避する)ことは、他のオプションです。しかし、それらもエスケープするのがより一般的な方法なので、+ 1。
ピーター
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.