क्या बैश में ट्यूपल्स पर लूप करना संभव है?
एक उदाहरण के रूप में, यह बहुत अच्छा होगा यदि निम्नलिखित काम करें:
for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done
वहाँ एक समाधान है कि किसी तरह मुझे tuples पर पाश है?
क्या बैश में ट्यूपल्स पर लूप करना संभव है?
एक उदाहरण के रूप में, यह बहुत अच्छा होगा यदि निम्नलिखित काम करें:
for (i,j) in ((c,3), (e,5)); do echo "$i and $j"; done
वहाँ एक समाधान है कि किसी तरह मुझे tuples पर पाश है?
जवाबों:
$ for i in c,3 e,5; do IFS=","; set -- $i; echo $1 and $2; done
c and 3
e and 5
इसके set(से man builtins) उपयोग के बारे में :
विकल्प प्रसंस्करण के बाद शेष किसी भी तर्क को स्थितिगत मापदंडों के लिए मान के रूप में माना जाता है और इसे $ 1, $ 2, ... के क्रम में सौंपा जाता है।
IFS=","क्षेत्र विभाजक तो हर सेट $iमें ही खंडित हो जाता है $1और $2सही ढंग से।
इस ब्लॉग के माध्यम से ।
संपादित करें: @SLACEDIAMOND द्वारा सुझाए गए अनुसार अधिक सही संस्करण:
$ OLDIFS=$IFS; IFS=','; for i in c,3 e,5; do set -- $i; echo $1 and $2; done; IFS=$OLDIFS
c and 3
e and 5
IFSअगर यह इंगित करना है कि कमांड लाइन पर चलाया जाता है तो बस सहेजा जाना चाहिए और अपने मूल मूल्य पर रीसेट करना चाहिए। इसके अलावा, नया IFSएक बार सेट किया जा सकता है, लूप के चलने से पहले, हर पुनरावृत्ति के बजाय।
set -- $i
IFS, केवल इसे setकमांड के लिए सेट करें for i in c,3 e,5; do IFS="," set -- $i; echo $1 and $2; done:। कृपया अपना उत्तर संपादित करें: यदि सभी पाठक सूचीबद्ध समाधानों में से केवल एक का चयन करेंगे, तो पूर्ण विकास इतिहास को पढ़ने में कोई समझदारी नहीं है। इस शांत चाल के लिए धन्यवाद!
tuples="a,1 b,2 c,3"और उपयोग करता हूं IFS=',', और c,3 e,5उपयोग के बजाय $tuplesयह बिल्कुल भी प्रिंट नहीं करता है। लेकिन इसके बजाय अगर मैं IFS=','केवल doलूप के लिए कीवर्ड के बाद रखता हूं , तो यह अच्छी $tuplesतरह से और साथ ही साथ लैटरल मानों का उपयोग करते समय काम करता है। बस यह कहने लायक था।
IFSपुनरावृत्तियों को विभाजित करने के लिए उपयोग करता है। यदि आप किसी सरणी पर लूप करते हैं, जैसे कि लूप के लिए arr=("c,3" "e,5")रखा जाता है IFS, तो $iवसीयत का मूल्य बस cऔर eहोगा, यह अलग हो जाएगा 3और 5इसलिए setसही तरीके से पार्स $iनहीं होगा क्योंकि पार्स करने के लिए कुछ भी नहीं होगा। इसका मतलब यह है कि अगर इट्रेट करने के मूल्यों को इनलेट नहीं किया जाता है, तो IFSउन्हें लूप के अंदर रखा जाना चाहिए, और बाहरी मान वेरिएबल के लिए इच्छित विभाजक का सम्मान करना चाहिए। इसके मामलों में $tuplesबस होना चाहिए IFS=जो डिफ़ॉल्ट है और व्हॉट्सएप पर विभाजित होता है।
मेरा मानना है कि यह समाधान दूसरों की तुलना में थोड़ा क्लीनर है, जो कि इस बैश स्टाइल गाइड के लिए एच / टी को दिखाता है कि कैसे पढ़ने के लिए एक सीमांकक पर स्ट्रिंग्स को विभाजित करने और उन्हें अलग-अलग चर को असाइन करने के लिए उपयोग किया जा सकता है।
for i in c,3 e,5; do
IFS=',' read item1 item2 <<< "${i}"
echo "${item1}" and "${item2}"
done
सेटिंग / रीसेट किए बिना @ eduardo-ivanec द्वारा दिए गए उत्तर के आधार पर IFS, कोई भी बस कर सकता है:
for i in "c 3" "e 5"
do
set -- $i
echo $1 and $2
done
उत्पादन:
c and 3
e and 5
साहचर्य सरणी का उपयोग करें (इसे शब्दकोश / हैशपॉप के रूप में भी जाना जाता है):
declare -A pairs=(
[c]=3
[e]=5
)
for key in "${!pairs[@]}"; do
value="${pairs[$key]}"
echo "key is $key and value is $value"
done
Bash4.0 + के लिए काम करता है।
यदि आपको जोड़े के बजाय त्रिकोणीय की आवश्यकता है, तो आप अधिक सामान्य दृष्टिकोण का उपयोग कर सकते हैं:
animals=(dog cat mouse)
declare -A sound=(
[dog]=barks
[cat]=purrs
[mouse]=cheeps
)
declare -A size=(
[dog]=big
[cat]=medium
[mouse]=small
)
for animal in "${animals[@]}"; do
echo "$animal ${sound[$animal]} and it is ${size[$animal]}"
done
GNU bash, version 4.4.23(1)-release-(x86_64-apple-darwin17.5.0)था, जो कि काढ़ा के माध्यम से स्थापित किया गया था, इसलिए YMMV।
GNU bash, version 4.3.11(1)-release-(x86_64-pc-linux-gnu)docker कंटेनर के भीतर Ubuntu 14.04 से काम किया ।
-Aहमारे पास है -a।
declare -a indices=(1 2 3); declare -a sound=(barks purrs cheeps); declare -a size=(big medium small)आदि की तरह यह अभी तक टर्मिनल में कोशिश नहीं की है, लेकिन मुझे लगता है कि यह काम करना चाहिए।
c=('a' 'c')
n=(3 4 )
for i in $(seq 0 $((${#c[*]}-1)))
do
echo ${c[i]} ${n[i]}
done
कभी-कभी अधिक काम आ सकता है।
uglyभाग को समझाने के लिए , जैसा कि टिप्पणियों में दिया गया है:
seq 0 2 संख्याओं के अनुक्रम का उत्पादन करता है 0 1 2. $ (cmd) कमांड प्रतिस्थापन है, इसलिए इस उदाहरण के लिए आउटपुट है seq 0 2, जो संख्या अनुक्रम है। लेकिन क्या ऊपरी बाध्य है $((${#c[*]}-1))?
$ ((कुछ)) अंकगणितीय विस्तार है, इसलिए $ ((3 + 4)) 7 है। हमारी अभिव्यक्ति है ${#c[*]}-1, इसलिए कुछ - 1. बहुत सरल, अगर हम जानते हैं कि क्या ${#c[*]}है।
c एक सरणी है, c [*] सिर्फ संपूर्ण सरणी है, $ {# c [*]} सरणी का आकार है जो हमारे मामले में 2 है। अब हम सब कुछ वापस रोल: for i in $(seq 0 $((${#c[*]}-1)))है for i in $(seq 0 $((2-1)))है for i in $(seq 0 1)है for i in 0 1। क्योंकि एरे में अंतिम तत्व का एक इंडेक्स है जो एरे की लंबाई है - 1।
for i in $(seq 0 $(($#c[*]}-1))); do [...]
GNU समानांतर का उपयोग:
parallel echo {1} and {2} ::: c e :::+ 3 5
या:
parallel -N2 echo {1} and {2} ::: c 3 e 5
या:
parallel --colsep , echo {1} and {2} ::: c,3 e,5
gnu parallel
brew install parallel
printfएक प्रक्रिया प्रतिस्थापन में उपयोग करना :
while read -r k v; do
echo "Key $k has value: $v"
done < <(printf '%s\n' 'key1 val1' 'key2 val2' 'key3 val3')
Key key1 has value: val1
Key key2 has value: val2
Key key3 has value: val3
ऊपर की आवश्यकता है bash। यदि bashउपयोग नहीं किया जा रहा है तो सरल पाइपलाइन का उपयोग करें:
printf '%s\n' 'key1 val1' 'key2 val2' 'key3 val3' |
while read -r k v; do echo "Key $k has value: $v"; done
do echo $key $value
done < file_discriptor
उदाहरण के लिए:
$ while read key value; do echo $key $value ;done <<EOF
> c 3
> e 5
> EOF
c 3
e 5
$ echo -e 'c 3\ne 5' > file
$ while read key value; do echo $key $value ;done <file
c 3
e 5
$ echo -e 'c,3\ne,5' > file
$ while IFS=, read key value; do echo $key $value ;done <file
c 3
e 5
थोड़ा और अधिक शामिल है, लेकिन उपयोगी हो सकता है:
a='((c,3), (e,5))'
IFS='()'; for t in $a; do [ -n "$t" ] && { IFS=','; set -- $t; [ -n "$1" ] && echo i=$1 j=$2; }; done
लेकिन क्या होगा यदि ट्यूपल k / v से अधिक है जो एक साहचर्य सरणी पकड़ सकता है? यदि यह 3 या 4 तत्व है तो क्या होगा? इस अवधारणा पर विस्तार किया जा सकता है:
###---------------------------------------------------
### VARIABLES
###---------------------------------------------------
myVars=(
'ya1,ya2,ya3,ya4'
'ye1,ye2,ye3,ye4'
'yo1,yo2,yo3,yo4'
)
###---------------------------------------------------
### MAIN PROGRAM
###---------------------------------------------------
### Echo all elements in the array
###---
printf '\n\n%s\n' "Print all elements in the array..."
for dataRow in "${myVars[@]}"; do
while IFS=',' read -r var1 var2 var3 var4; do
printf '%s\n' "$var1 - $var2 - $var3 - $var4"
done <<< "$dataRow"
done
तब आउटपुट कुछ इस तरह दिखाई देगा:
$ ./assoc-array-tinkering.sh
Print all elements in the array...
ya1 - ya2 - ya3 - ya4
ye1 - ye2 - ye3 - ye4
yo1 - yo2 - yo3 - yo4
और तत्वों की संख्या अब सीमा के बिना है। वोट की तलाश में नहीं; बस जोर से सोच रहा था। आरईएफ 1 , आरईएफ 2
ऐसे मामलों में जहां मेरी तुच्छ परिभाषाएं अधिक जटिल हैं, मैं उन्हें एक हेरेडोक में रखना पसंद करता हूं:
while IFS=", " read -ra arr; do
echo "${arr[0]} and ${arr[1]}"
done <<EOM
c, 3
e, 5
EOM
यह कुछ वांछित पृथक्करण वर्ण पर रेखाओं को विभाजित करने के साथ एक हेरेडोक की लाइनों पर लूपिंग को जोड़ती है ।