बैश में तार की एक सरणी के माध्यम से लूप?


1499

मैं एक स्क्रिप्ट लिखना चाहता हूं जो 15 स्ट्रिंग्स (संभवतः सरणी?) के माध्यम से लूप करती है?

कुछ इस तरह:

for databaseName in listOfNames
then
  # Do something
end

जवाबों:


2383

आप इसे इस तरह से उपयोग कर सकते हैं:

## declare an array variable
declare -a arr=("element1" "element2" "element3")

## now loop through the above array
for i in "${arr[@]}"
do
   echo "$i"
   # or do whatever with individual element of the array
done

# You can access them using echo "${arr[0]}", "${arr[1]}" also

मल्टी-लाइन ऐरे डिक्लेरेशन के लिए भी काम करता है

declare -a arr=("element1" 
                "element2" "element3"
                "element4"
                )

775

यह संभव है, निश्चित रूप से।

for databaseName in a b c d e f; do
  # do something like: echo $databaseName
done 

देखें , के लिए बैश लूप्स जबकि और जब तक जानकारी के लिए।


18
इस दृष्टिकोण के साथ समस्या क्या है? साधारण मामलों में यह काम करने लगता है और फिर, @ शुभ के जवाब से अधिक सहज है।
डॉ। जान-फिलिप गेर्के

17
यह विशेष रूप से कमांड प्रतिस्थापन के साथ अच्छी तरह से काम करता है, जैसे for year in $(seq 2000 2013)
ब्रैड कोच

22
समस्या यह है कि उन्होंने एक सरणी के माध्यम से पुनरावृति के बारे में पूछा।
मंगल

20
यदि आप एक से अधिक स्थानों पर एक ही सरणी पर चलना चाहते हैं, तो 'घोषित' दृष्टिकोण सबसे अच्छा काम करता है। यह दृष्टिकोण क्लीनर है लेकिन कम लचीला है।
स्टैम्पकोड

15
यह # 1 क्यों नहीं है? यह क्लीनर है, और आप आसानी से एक स्ट्रिंग सेट करके आसानी से सरणी का उपयोग कर सकते हैं, अर्थात DATABASES="a b c d e f"
नेरमाडस्टर

201

उन उत्तरों में से कोई भी एक काउंटर शामिल नहीं है ...

#!/bin/bash
## declare an array variable
declare -a array=("one" "two" "three")

# get length of an array
arraylength=${#array[@]}

# use for loop to read all values and indexes
for (( i=1; i<${arraylength}+1; i++ ));
do
  echo $i " / " ${arraylength} " : " ${array[$i-1]}
done

आउटपुट:

1  /  3  :  one
2  /  3  :  two
3  /  3  :  three

7
यह स्वीकृत उत्तर होना चाहिए, केवल एक है जो काम करता है जब सरणी तत्वों में रिक्त स्थान होते हैं।
jesjimher

1
यह सिर्फ एक काउंटर के साथ उदाहरण के आउटपुट के लिए है। इसे बदलने के लिए यह काफी तुच्छ है, और बस एक ही काम करता है।
caktux

7
अंत में गूंज छोटी गाड़ी है। आपको स्थिरांक को उद्धृत करने की आवश्यकता नहीं है, आपको विस्तार को उद्धृत करने की आवश्यकता है, या सुरक्षित रूप से केवल दोनों को निम्नानुसार उद्धृत कर सकते हैं: echo "$i / ${arraylength} : ${array[$i-1]}"- अन्यथा, यदि आपके $iग्लोब में यह विस्तारित होगा, यदि इसमें एक टैब है तो इसे बदल दिया जाएगा। एक स्थान, आदि
चार्ल्स डफी

10
@bzeaman, निश्चित रूप से - लेकिन अगर आप ऐसी चीजों के बारे में सुस्त हैं, तो इसे कुछ सही साबित करने के लिए प्रासंगिक विश्लेषण की आवश्यकता होती है, और यदि संदर्भ बदल जाता है या कोड का पुन: उपयोग किया जाता है या अलग स्थान पर जो भी अन्य कारण एक अप्रत्याशित नियंत्रण प्रवाह संभव है। इसे मजबूत तरीके से लिखें और यह संदर्भ की परवाह किए बिना सही है।
चार्ल्स डफी 14

5
यह एक विरल सरणी के लिए काम नहीं करेगा, अर्थात यदि सरणी अनुपलब्ध तत्व है। उदाहरण के लिए, यदि आपके पास सरणी तत्व A [1] = 'xx', A [4] = 'yy' और A [9] = 'zz' है, तो लंबाई 3 होगी और लूप सभी तत्वों को संसाधित नहीं करेगा। ।
श्री एड।

144

हाँ

for Item in Item1 Item2 Item3 Item4 ;
  do
    echo $Item
  done

आउटपुट:

Item1
Item2
Item3
Item4

रिक्त स्थान को संरक्षित करने के लिए; एकल या डबल उद्धरण सूची प्रविष्टियाँ और डबल उद्धरण सूची विस्तार।

for Item in 'Item 1' 'Item 2' 'Item 3' 'Item 4' ;
  do
    echo "$Item"
  done

आउटपुट:

Item 1
Item 2
Item 3
Item 4

कई लाइनों पर सूची बनाने के लिए

for Item in Item1 \
            Item2 \
            Item3 \
            Item4
  do
    echo $Item
  done

आउटपुट:

Item1
Item2
Item3
Item4


सरल सूची चर

List=( Item1 Item2 Item3 )

या

List=(
      Item1 
      Item2 
      Item3
     )

सूची चर प्रदर्शित करें:

echo ${List[*]}

आउटपुट:

Item1 Item2 Item3

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

for Item in ${List[*]} 
  do
    echo $Item 
  done

आउटपुट:

Item1
Item2
Item3

एक सूची के माध्यम से जाने के लिए एक समारोह बनाएँ:

Loop(){
  for item in ${*} ; 
    do 
      echo ${item} 
    done
}
Loop ${List[*]}

सूची बनाने के लिए घोषित कीवर्ड (कमांड) का उपयोग करना, जिसे तकनीकी रूप से एक सरणी कहा जाता है:

declare -a List=(
                 "element 1" 
                 "element 2" 
                 "element 3"
                )
for entry in "${List[@]}"
   do
     echo "$entry"
   done

आउटपुट:

element 1
element 2
element 3

एक सहयोगी सरणी बनाना। एक शब्दकोष:

declare -A continent

continent[Vietnam]=Asia
continent[France]=Europe
continent[Argentina]=America

for item in "${!continent[@]}"; 
  do
    printf "$item is in ${continent[$item]} \n"
  done

आउटपुट:

 Argentina is in America
 Vietnam is in Asia
 France is in Europe

सूची में सीवीएस चर या फाइलें
आंतरिक क्षेत्र विभाजक को किसी स्थान से बदलना, जो आप चाहते हैं।
नीचे दिए गए उदाहरण में इसे अल्पविराम में बदल दिया गया है

List="Item 1,Item 2,Item 3"
Backup_of_internal_field_separator=$IFS
IFS=,
for item in $List; 
  do
    echo $item
  done
IFS=$Backup_of_internal_field_separator

आउटपुट:

Item 1
Item 2
Item 3

यदि उन्हें संख्या देने की आवश्यकता है:

` 

इसे बैक टिक कहा जाता है। वापस टिक के अंदर कमांड रखें।

`commend` 

यह आपके कीबोर्ड पर या टैब कुंजी के ऊपर नंबर एक के बगल में है। एक मानक अमेरिकी अंग्रेजी भाषा कीबोर्ड पर।

List=()
Start_count=0
Step_count=0.1
Stop_count=1
for Item in `seq $Start_count $Step_count $Stop_count`
    do 
       List+=(Item_$Item)
    done
for Item in ${List[*]}
    do 
        echo $Item
    done

आउटपुट है:

Item_0.0
Item_0.1
Item_0.2
Item_0.3
Item_0.4
Item_0.5
Item_0.6
Item_0.7
Item_0.8
Item_0.9
Item_1.0

चकत्ते व्यवहार के साथ और अधिक परिचित बनना:

एक फ़ाइल में एक सूची बनाएँ

cat <<EOF> List_entries.txt
Item1
Item 2 
'Item 3'
"Item 4"
Item 7 : *
"Item 6 : * "
"Item 6 : *"
Item 8 : $PWD
'Item 8 : $PWD'
"Item 9 : $PWD"
EOF

सूची और प्रदर्शन के लिए सूची फ़ाइल पढ़ें

List=$(cat List_entries.txt)
echo $List
echo '$List'
echo "$List"
echo ${List[*]}
echo '${List[*]}'
echo "${List[*]}"
echo ${List[@]}
echo '${List[@]}'
echo "${List[@]}"

BASH कमांडलाइन संदर्भ मैनुअल: शेल के लिए कुछ वर्णों या शब्दों का विशेष अर्थ।


7
ये गलत है। उद्धरण के साथ"${List[@]}" , सही होने की आवश्यकता है । गलत है। गलत है। कोशिश करें - आपको किसी अन्य संस्करण से नहीं बल्कि सही व्यवहार मिलेगा । ${List[@]}${List[*]}List=( "* first item *" "* second item *" )for item in "${List[@]}"; do echo "$item"; done
चार्ल्स डफी

हाँ विशेष वर्णों की व्याख्या हो जाती है, जो वांछनीय हो भी सकती है और नहीं भी। मैंने शामिल करने के उत्तर को अपडेट किया।
FireInTheSky

2
मैं अभी भी दृढ़ता से अधिक सही / मजबूत दृष्टिकोण दिखा सुझाव है कि पहले । लोग अक्सर पहला जवाब लेते हैं जो दिखता है कि यह काम करेगा; यदि उस उत्तर में छिपी हुई गुहाएं हैं, तो वे बाद में खुद को उजागर कर सकते हैं। (यह सिर्फ वाइल्डकार्ड कि हवाले से की कमी से टूट रहे हैं नहीं है, List=( "first item" "second item" )में विभाजित कर दिया जाएगा first, item, second, itemसाथ ही साथ)।
चार्ल्स डफी

आप एक उदाहरण के उपयोग से बचने पर भी विचार कर सकते हैं जो सर्वोत्तम प्रथाओं के उल्लंघन में लोगों को lsआउटपुट देने के लिए प्रेरित कर सकता है ।
चार्ल्स डफी

1
आप उन दावों का खंडन कर रहे हैं जो मैंने कभी नहीं किए। मैं बैश के शब्दार्थ से बहुत परिचित हूं - देखें stackoverflow.com/tags/bash/topusers
चार्ल्स डफी

108

4ndrew के जवाब के रूप में एक ही भावना में:

listOfNames="RA
RB
R C
RD"

# To allow for other whitespace in the string:
# 1. add double quotes around the list variable, or
# 2. see the IFS note (under 'Side Notes')

for databaseName in "$listOfNames"   #  <-- Note: Added "" quotes.
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R C
# RD

B. नाम में कोई व्हाट्सएप नहीं:

listOfNames="RA
RB
R C
RD"

for databaseName in $listOfNames  # Note: No quotes
do
  echo "$databaseName"  # (i.e. do action / processing of $databaseName here...)
done

# Outputs
# RA
# RB
# R
# C
# RD

टिप्पणियाँ

  1. दूसरे उदाहरण में, उपयोग listOfNames="RA RB R C RD"का समान आउटपुट है।

डेटा में लाने के अन्य तरीकों में शामिल हैं:

स्टडिन से पढ़ें

# line delimited (each databaseName is stored on a line)
while read databaseName
do
  echo "$databaseName"  # i.e. do action / processing of $databaseName here...
done # <<< or_another_input_method_here
  1. बैश IFS "लाइन सेपरेटर" [ 1 ] परिसीमन को अन्य व्हाट्सएप (यानी IFS='\n', या MacOS के लिए IFS='\r') की अनुमति देने के लिए स्क्रिप्ट में निर्दिष्ट किया जा सकता है।
  2. मुझे स्वीकृत उत्तर भी पसंद है :) - मैंने इन स्निपेट्स को अन्य सहायक तरीकों के रूप में शामिल किया है जो प्रश्न का उत्तर भी देते हैं।
  3. #!/bin/bashस्क्रिप्ट फ़ाइल के शीर्ष पर शामिल निष्पादन पर्यावरण को इंगित करता है।
  4. मुझे यह पता लगाने में महीनों लग गए कि यह कैसे कोड किया जाए :)

अन्य स्रोत ( लूप पढ़ते समय )


यह धारणा बनाता है कि ईओएल को स्ट्रिंग विभाजक के रूप में उपयोग किया जाता है और इसलिए, स्ट्रिंग्स के भीतर व्हाट्सएप की अनुमति है। हालांकि, व्हाट्सएप के साथ तार को सब्सट्रिंग में अलग किया जाता है, जो बहुत खराब है। मुझे लगता है कि यह उत्तर stackoverflow.com/a/23561892/1083704 बेहतर है।
वैल

1
@Val, मैंने एक संदर्भ के साथ कोड टिप्पणी जोड़ी IFS। (सभी के लिए, IFSएक विशिष्ट परिसीमा को निर्दिष्ट करने देता है, जो अन्य व्हाट्सएप को सब्सट्रेट में अलग किए बिना तार में शामिल करने की अनुमति देता है)।
user2533809

7
यह मेरे लिए काम नहीं करता है। $databaseNameबस पूरी सूची में शामिल है, इस प्रकार केवल एक पुनरावृत्ति करता है।
एलिकएल्ज़िन-किलाका

@ AlikElzin-kilaka इस समस्या को हल करने के लिए मेरा उत्तर नीचे दिया गया है ताकि स्ट्रिंग की प्रत्येक पंक्ति के लिए लूप चलाया जा सके।
जेमी

42

आप वाक्य रचना का उपयोग कर सकते हैं ${arrayName[@]}

#!/bin/bash
# declare an array called files, that contains 3 values
files=( "/etc/passwd" "/etc/group" "/etc/hosts" )
for i in "${files[@]}"
do
    echo "$i"
done

31

आश्चर्य है कि किसी ने इसे अभी तक पोस्ट नहीं किया है - यदि आपको सरणी के माध्यम से लूप करते समय तत्वों के सूचकांक की आवश्यकता है, तो आप यह कर सकते हैं:

arr=(foo bar baz)

for i in ${!arr[@]}
do
    echo $i "${arr[i]}"
done

आउटपुट:

0 foo
1 bar
2 baz

मुझे यह "पारंपरिक" फॉर-लूप स्टाइल ( for (( i=0; i<${#arr[@]}; i++ ))) की तुलना में बहुत अधिक सुरुचिपूर्ण लगता है ।

( ${!arr[@]}और $iउन्हें उद्धृत करने की आवश्यकता नहीं है क्योंकि वे सिर्फ संख्या हैं; कुछ उन्हें वैसे भी उद्धृत करने का सुझाव देंगे, लेकिन यह सिर्फ व्यक्तिगत प्राथमिकता है।)


2
यह वास्तव में चुना हुआ उत्तर होना चाहिए। 1: यह सरल और पढ़ने में आसान है। 2: यह व्हाट्सएप को सही तरीके से संभालता है, कोई भी IFS बकवास नहीं कर रहा है। 3: यह विरल सरणियों को सही ढंग से संभालता है।
mrm

20

यह भी पढ़ने में आसान है:

FilePath=(
    "/tmp/path1/"    #FilePath[0]
    "/tmp/path2/"    #FilePath[1]
)

#Loop
for Path in "${FilePath[@]}"
do
    echo "$Path"
done

4
यह एक स्पष्ट और मेरे लिए काम किया है (फ़ाइलपैथ सरणी तत्वों में रिक्त स्थान और चर प्रतिस्थापन के साथ) केवल जब मैं फ़ाइल फ़ाइल सरणी परिभाषा से पहले आईएफएस चर सही ढंग से सेट करता हूं : IFS=$'\n' यह इस परिदृश्य में अन्य समाधानों के लिए भी काम कर सकता है।
एलन फोर्सिथ

8

स्क्रिप्ट या कार्यों के लिए संक्षिप्त सरणी:

के अलावा anubhava 'सही जवाब है: अगर पाश के लिए बुनियादी वाक्य रचना है:

for var in "${arr[@]}" ;do ...$var... ;done

में एक विशेष मामला है:

जब एक स्क्रिप्ट या एक समारोह चल रहा है, तर्क कमांड लाइन में पारित करने के लिए आवंटित किया जाएगा $@सरणी चर, आप तक पहुंच सकते हैं $1, $2, $3, और इतने पर।

इसे (परीक्षण के लिए) आबाद किया जा सकता है

set -- arg1 arg2 arg3 ...

इस सरणी पर एक लूप बस लिखा जा सकता है:

for item ;do
    echo "This is item: $item."
  done

ध्यान दें कि आरक्षित कार्य inमौजूद नहीं है और कोई सरणी नाम भी नहीं है!

नमूना:

set -- arg1 arg2 arg3 ...
for item ;do
    echo "This is item: $item."
  done
This is item: arg1.
This is item: arg2.
This is item: arg3.
This is item: ....

ध्यान दें कि यह इसी से अधिक है

for item in "$@";do
    echo "This is item: $item."
  done

फिर एक स्क्रिप्ट में :

#!/bin/bash

for item ;do
    printf "Doing something with '%s'.\n" "$item"
  done

एक स्क्रिप्ट में इस सहेजें myscript.sh, chmod +x myscript.shहै, तो

./myscript.sh arg1 arg2 arg3 ...
Doing something with 'arg1'.
Doing something with 'arg2'.
Doing something with 'arg3'.
Doing something with '...'.

एक समारोह में एक ही :

myfunc() { for item;do cat <<<"Working about '$item'."; done ; }

फिर

myfunc item1 tiem2 time3
Working about 'item1'.
Working about 'tiem2'.
Working about 'time3'.

7
listOfNames="db_one db_two db_three"
for databaseName in $listOfNames
do
  echo $databaseName
done

या केवल

for databaseName in db_one db_two db_three
do
  echo $databaseName
done

7

सरल तरीका :

arr=("sharlock"  "bomkesh"  "feluda" )  ##declare array

len=${#arr[*]}  # it returns the array length

#iterate with while loop
i=0
while [ $i -lt $len ]
do
    echo ${arr[$i]}
    i=$((i+1))
done


#iterate with for loop
for i in $arr
do
  echo $i
done

#iterate with splice
 echo ${arr[@]:0:3}

6

घोषित सरणी Korn शेल के लिए काम नहीं करती है। कोर्न शेल के लिए नीचे दिए गए उदाहरण का उपयोग करें:

promote_sla_chk_lst="cdi xlob"

set -A promote_arry $promote_sla_chk_lst

for i in ${promote_arry[*]};
    do
            echo $i
    done

2
अपने कोड को अच्छा बनाने के लिए संपादक में कोड हाइलाइटर आज़माएं।
कबूतर

5
जानकर अच्छा लगा, लेकिन यह सवाल बैश के बारे में है।
ब्रैड कोच

1
यहाँ बहुत कीड़े हैं। रिक्त स्थान के साथ सूची प्रविष्टियाँ नहीं हो सकती हैं, ग्लोब वर्णों के साथ सूची प्रविष्टियाँ नहीं हो सकती हैं। for i in ${foo[*]}मूल रूप से हमेशा गलत चीज है - for i in "${foo[@]}"वह रूप है जो मूल सूची की सीमाओं को बनाए रखता है और ग्लोब विस्तार को रोकता है। और गूंज की जरूरत हैecho "$i"
चार्ल्स डफी

4

यह user2533809 के उत्तर के समान है, लेकिन प्रत्येक फ़ाइल को एक अलग कमांड के रूप में निष्पादित किया जाएगा।

#!/bin/bash
names="RA
RB
R C
RD"

while read -r line; do
    echo line: "$line"
done <<< "$names"

3

यदि आप कोर्न शेल का उपयोग कर रहे हैं, तो " सेट-ए-डेटाबेसनाम " है, अन्यथा " घोषणा-ए डेटाबेसनाम " है

सभी गोले पर काम करने वाली स्क्रिप्ट लिखने के लिए,

 set -A databaseName=("db1" "db2" ....) ||
        declare -a databaseName=("db1" "db2" ....)
# now loop 
for dbname in "${arr[@]}"
do
   echo "$dbname"  # or whatever

done

यह सभी गोले पर काम होना चाहिए।


3
नहीं, यह नहीं है: $ bash --versionGNU बैश, संस्करण 4.3.33 (0) -release (amd64-portbld-freebsd10.0) $ set -A databaseName=("db1" "db2" ....) || declare -a databaseName=("db1" "db2" ....)bash: अप्रत्याशित टोकन के पास सिंटैक्स त्रुटि `('
Bernie Reiter

2

इसे इस्तेमाल करे। यह काम कर रहा है और परीक्षण किया है।

for k in "${array[@]}"
do
    echo $k
done

# For accessing with the echo command: echo ${array[0]}, ${array[1]}

3
यह वास्तव में सही ढंग से काम नहीं करता है। कोशिश करो array=( "hello world" ), या arrray=( "*" ); पहले मामले में यह प्रिंट helloऔर worldअलग-अलग होगा, दूसरे में यह फाइलों की एक सूची प्रिंट करेगा*
चार्ल्स डफी

6
... शेल में कुछ "परीक्षण" करने से पहले, कोने के मामलों की जांच करना सुनिश्चित करें, जो व्हॉट्सएप और ग्लब्स दोनों में से हैं।
चार्ल्स डफी

2

हर बैश स्क्रिप्ट / सत्र की संभावित पहली पंक्ति:

say() { for line in "${@}" ; do printf "%s\n" "${line}" ; done ; }

उदाहरण के लिए उपयोग करें:

$ aa=( 7 -4 -e ) ; say "${aa[@]}"
7
-4
-e

विचार कर सकते हैं: यहाँ विकल्प के रूप में echoव्याख्या -eकरता है



2

मुझे वास्तव में इसके लिए कुछ इस तरह की आवश्यकता थी:

for i in $(the_array); do something; done

उदाहरण के लिए:

for i in $(ps -aux | grep vlc  | awk '{ print $2 }'); do kill -9 $i; done

(Vlc के साथ सभी प्रक्रियाओं को उनके नाम पर मार देगा)


1

मैं एक git pullअद्यतन के लिए अपनी परियोजनाओं की एक सरणी के माध्यम से पाश :

#!/bin/sh
projects="
web
ios
android
"
for project in $projects do
    cd  $HOME/develop/$project && git pull
end

7
हालांकि यह कोड स्निपेट प्रश्न को हल कर सकता है, जिसमें स्पष्टीकरण सहित वास्तव में आपकी पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है। कृपया अपने कोड को व्याख्यात्मक टिप्पणियों के साथ भीड़ न दें, इससे कोड और स्पष्टीकरण दोनों की पठनीयता कम हो जाती है!
kayess
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.