Değişkenlerle Döngü


16

Yaklaşık 20 farklı sunucuda rsync kullanmak ve dosyaları güncellemek için bir bash betiği yazıyorum.

Ben rsync parçası anladım var. Sorun yaşadığım değişkenler listesinden geçiyor.

Benim senaryom şu ana kadar benziyor:

#!/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]İlişkili değişkenin değeri nerede olmalıdır. Bu yüzden i = 1 olduğunda $ SERVER1 değerini yankılamalıyım.

Ben de dahil olmak üzere, bunun birkaç yineleme denedim

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

Senaryo yazmamın üzerinden uzun zaman geçti, bu yüzden bir şey eksik olduğumu biliyorum. Ayrıca, son 11 yıldır kullandığım C # kullanarak yapabileceğim şeyleri karıştırıyorum.

Yapmaya çalıştığım şey mümkün mü? Yoksa bu değerleri bir diziye koyup dizide döngü yapmalı mıyım? Aynı şey üretim IP adresleri yanı sıra konum adları için gerekir.

Bu, uzak sunucudaki dosyaları senkronize etmek için kullanacağım bir kod bloğunu tekrarlamak zorunda kalmamak için bir çaba.


Tüm yanıtlar ve yorumlar için teşekkürler. Dizi yaklaşımı muhtemelen daha fazla alacaktır.
Paul Stoner

Yanıtlar:


33

Bir dizi kullanın.

#! /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; ve dizi öğelerinin önüne / arkasına / arasına keyfi boşluk koyabileceğinizi unutmayın, böylece (istenirse) OP'de olduğu gibi her satıra bir öğe koyabilirsiniz.
ruakh

@ruakh: teşekkürler, neler yapılabileceğini göstermek için güncellendi.
choroba

28

Diğer cevapların işaret ettiği gibi, bir dizi bunu yapmanın en uygun yoludur. Bununla birlikte, bütünlük için, tam olarak istediğiniz şey dolaylı genişlemedir . Aşağıdaki gibi yeniden yazıldığında, örneğiniz bu yöntemi kullanarak da çalışır:

#!/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

Sadece IP adreslerinin listesini fordöngüye koymakta sorun yaşıyorsanız, ihtiyacınız olan şeyleri yinelemek için bazı destek genişletmeleri de kullanabilirsiniz:

#!/bin/bash

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

Ancak (muhtemelen küme ayracı genişletilmiş) listeyi yeniden kullanmanız gerekiyorsa, bir diziyi başlatmak için listeyi kullanmak şu yol olacaktır:

#!/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

Muhtemelen dizi cevaplarından biri kendimle giderken, isimlerin doğrudan üzerine dönmenin mümkün olduğunu belirtmek isterim. Yapabilirsin

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

veya 4.3 ve sonraki sürümlerde aşağıdakileri kullanabilirsiniz nameref:

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

<4.3 çözeltisi için şapka uç ilkkachu .


2
Dolaylı genişletme ( ${!var}), Bash'in eski sürümleriyle de çalışır:foo1=aa; foo2=bbb; foox=cccc; for p in "${!foo@}"; do echo "$p = ${!p}"; done
ilkkachu

@ilkkachu Yardımınız için teşekkürler. Cevabımı güncelledim.
kojiro

6

Bir dizi kullanmanız gerektiğini söyleyen herkes doğrudur, ancak - akademik bir alıştırma olarak - bir sayı ile biten ayrı değişkenlerle (SERVER1, SERVER2, vb.) Yapmaya kararlı olsaydınız, böyle yapardınız o:

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

evalgüvenli kullanımı zordur. Evet bu işe yarayabilir, ancak bash dolaylı genişleme genel olarak daha iyi bir yoldur.
Peter Cordes

Alışkanlık. Kabuk betikleri yazmaya başladığımda, bash'ta bile, dolaylı bir genişleme yoktu. Eğer düzgün kaçmayı anlarsanız "eval" tamamen güvenlidir. Yine de, dolaylı genişlemenin daha iyi olduğunu kabul ediyorum ... ama eski yollar hala işe yarıyor. Zaten bu durumda ben de yapmam. Bir dizi kullanırdım!
Beam Davis

Bu durumda, çift tırnak kaçmamış o haber, böylece sonra evalsahip, yapılır echo $SERVER1, değil echo "$SERVER1". Evet güvenle kullanmak mümkündür, ancak güvenli olmayan veya istediğiniz şekilde kullanımı çok kolay !
Peter Cordes

Bir sunucu adı boşluk içermeyeceğinden, zaten bu durumda önemli olmazdı ... ama haklısınız, çift tırnak işaretleri kaçmalı. Cevap düzeltildi!
Beam Davis

Doğru, çift tırnakları tamamen kaldırmak (herhangi bir şeyi korudukları yanıltıcı izlenimi önlemek için) diğer seçenek olacaktır. Ama onlardan kaçmak daha genel bir yol, yani +1.
Peter Cordes
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.