चर के माध्यम से लूप


16

मैं लगभग 20 विभिन्न सर्वरों पर rsync और फ़ाइलों को अपडेट करने के लिए एक बैश स्क्रिप्ट लिख रहा हूं।

मेरे पास 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

मुझे स्क्रिप्ट किए हुए काफी समय हो चुका है इसलिए मुझे पता है कि मुझे कुछ याद आ रहा है। इसके अलावा मुझे यकीन है कि मैं C # का उपयोग करके कर सकता हूं, जिसे मैंने पिछले 11 वर्षों से उपयोग किया है।

क्या मैं भी संभव करने की कोशिश कर रहा हूं? या मुझे इन मूल्यों को एक सरणी में रखना चाहिए और सरणी के माध्यम से लूप करना चाहिए? मुझे उत्पादन आईपी पते के साथ-साथ स्थान नामों के लिए भी यही बात चाहिए।

यह सब एक प्रयास है कि मैं रिमोट सर्वर पर फ़ाइलों को सिंक करने के लिए उपयोग किए जाने वाले कोड का एक ब्लॉक नहीं दोहराऊं।


सभी प्रतिक्रियाओं और टिप्पणियों के लिए धन्यवाद। मैं सरणी दृष्टिकोण लेने की संभावना से अधिक करूंगा।
पॉल स्टोनर

जवाबों:


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; और ध्यान दें कि आप सरणी तत्वों के बीच / पहले / बाद में मनमाने ढंग से व्हाट्सएप डाल सकते हैं, इसलिए आप (यदि चाहें) ओपी के अनुसार प्रति पंक्ति एक तत्व डाल सकते हैं।
21

@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

यदि आप केवल आईपी पते की सूची को 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

हालांकि मैं संभवतः किसी एक सरणी के साथ खुद को उत्तर देता हूं, मैं यह बताना चाहता हूं कि सीधे नामों पर लूप करना संभव है। तुम कर सकते हो

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

या, 4.3 और ऊपर में, आप एक का उपयोग कर सकते हैं nameref:

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

<४.३ समाधान के लिए टोपी टिप इल्काचू


2
अप्रत्यक्ष विस्तार ( ${!var}) बाश के पुराने संस्करणों के साथ भी काम करता है:foo1=aa; foo2=bbb; foox=cccc; for p in "${!foo@}"; do echo "$p = ${!p}"; done
ilkachachu

@ilkkachu सहायता के लिए धन्यवाद। मैंने अपना उत्तर अपडेट कर दिया है।
कोजिरो

6

हर किसी ने कहा कि आपको एक सरणी का उपयोग करना चाहिए सही है, लेकिन - एक अकादमिक अभ्यास के रूप में - यदि आप इसे एक संख्या में समाप्त होने वाले अलग-अलग चर (SERVER1, SERVER2, आदि) के साथ करने के लिए दृढ़ थे, तो यह है कि आप कैसे करेंगे यह:

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

evalसुरक्षित रूप से उपयोग करना कठिन है। हाँ, यह काम कर सकता है, लेकिन अप्रत्यक्ष विस्तार को सामान्य रूप से बेहतर तरीका है।
पीटर Cordes

आदत। जब मैंने शेल स्क्रिप्ट लिखना शुरू किया, तब भी बैश में, अप्रत्यक्ष विस्तार नहीं था। "eval" पूरी तरह से सुरक्षित है यदि आप समझते हैं कि कैसे ठीक से बचना है। फिर भी, मैं आपसे सहमत हूं कि अप्रत्यक्ष विस्तार बेहतर है ... लेकिन पुराने तरीके अभी भी काम करते हैं। मैं वैसे भी इस मामले में नहीं होगा। मैं एक सरणी का उपयोग करेंगे!
बीम डेविस

इस स्थिति में, ध्यान दें कि आप दोहरे उद्धरण चिह्नों से बच नहीं पाए, इसलिए किए जाने के बाद eval, आपके पास है echo $SERVER1, नहीं echo "$SERVER1"। हाँ, सुरक्षित रूप से उपयोग करना संभव है, लेकिन बहुत आसान है कि आप इसका उपयोग न करें या न करें कि आपका इरादा कैसा है!
पीटर कॉर्ड्स

चूंकि सर्वर नाम में कोई स्थान नहीं होता है, इसलिए इस मामले में वैसे भी कोई फर्क नहीं पड़ता ... लेकिन आप सही हैं, दोहरे-उद्धरण से बच जाना चाहिए। जवाब में तय किया!
बीम डेविस

सही, दोहरे-उद्धरणों को पूरी तरह से हटा देना (भ्रामक धारणा से बचने के लिए कि वे किसी भी चीज़ की रक्षा कर रहे थे) दूसरा विकल्प होगा। लेकिन उनसे बचना भी अधिक सामान्य तरीका है, इसलिए +1।
पीटर कॉर्ड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.