अनुक्रमणिका और मान दोनों को मुद्रित करना, सरणियों पर लूपिंग करना


184

मैं कुछ इस तरह करना चाहता हूं:

foo=( )
foo[0]="bar"
foo[35]="baz"
for((i=0;i<${#foo[@]};i++))
do
    echo "$i: ${foo[$i]}"
done
# Output:
# 0: bar
# 1: 

तो मैं इसके माध्यम से उपयोग करने के लिए पाश की कोशिश की:

foo=( )
foo[0]="bar"
foo[35]="baz"
for i in ${foo[@]}
do
    echo "?: $i"
done
# Output:
# ?: bar
# ?: naz

लेकिन यहां मुझे इंडेक्स वैल्यू की जानकारी नहीं है।

मुझे पता है कि आप ऐसा कुछ कर सकते हैं

foo=( )
foo[0]="bar"
foo[35]="baz"
declare -p foo
# Output:
# declare -a foo='([0]="bar" [35]="baz")'

लेकिन, क्या आप इसे दूसरे तरीके से नहीं कर सकते?

जवाबों:


316

आपको संदर्भ"${!foo[@]}" ( संदर्भ ) के साथ सरणी कुंजियाँ मिलेंगी , इसलिए:

for i in "${!foo[@]}"; do 
  printf "%s\t%s\n" "$i" "${foo[$i]}"
done

जिसका अर्थ है कि सूचकांक उस $iसमय होंगे जब तत्वों को स्वयं तक पहुंचना होगा${foo[$i]}


6
महत्वपूर्ण नोट, पुनरावृत्ति करते समय, शब्दों की एक अंतरिक्ष से अलग सूची एक सरणी नहीं है । इसे (a b c)एक सरणी में बदलने के लिए इसे लपेटें ।
ब्रीडली

4
के [@]और दोहरे उद्धरण चिह्नों के उपयोग का अर्थ है "शब्दों की अंतरिक्ष से अलग सूची" नहीं है। आपको वास्तविक सरणी कुंजियों की सूची मिलती है, भले ही व्यक्तिगत कुंजियों में व्हाट्सएप हो।
बजे ग्लेन जैकमैन

@glennjackman आप इसे और अधिक समझा सकते हैं The use of [@] and double quotes means it's not a "space separated list of words"
कसुन सियामबलपिटिया

1
"${foo[@]}"(सरणी) चर लेता है fooऔर इसे एक सरणी के रूप में विस्तारित करता है, अपने तत्वों की पहचान बनाए रखता है, अर्थात, उन्हें व्हाट्सएप पर विभाजित नहीं करता है। यदि foo=(x 'y z'), तो दो तर्कों के साथ f "${foo[@]}"कॉल करता fहै, xऔर 'y z'। मेटाडेटा क्वेरी "${!foo[@]}"और "${#foo[@]}"इसी तरह fooएक सरणी के रूप में कार्य करता है ।
बॉलपॉइंटबैन

सही उत्तर, लेकिन यह संदर्भ असंवेदनशील है। यह उत्तर सहायक रूप से बताता है: " "${!foo[@]}"सरणी में निर्धारित सभी अनुक्रमितों की सूची है"।
pjhsea

17

आप हमेशा पुनरावृत्ति परम का उपयोग कर सकते हैं:

ITER=0
for I in ${FOO[@]}
do  
    echo ${I} ${ITER}
    ITER=$(expr $ITER + 1)
done

5
((ITER++))आधुनिक बैश में
डेविड टोनहोफर

पोस्ट-इन्क्रीमेंट क्यों? आप केवल बढ़े हुए मूल्य चाहते हैं, इसलिए ((++ ITER)) सीधे तौर पर आपके द्वारा किए गए कार्यों का अधिक विवरण है ....
माइक डब्ल्यूडब्ल्यू

3
नहीं, "हमेशा" नहीं। एक हैश में "छेद" हो सकते हैं, जिसका अर्थ है कि सभी संख्याएं एक सूचकांक नहीं हैं। आपके उदाहरण में $ {ITER} हमेशा $ {I} का सूचकांक नहीं है।
मार्को

10
INDEX=0
for i in $list; do 
    echo ${INDEX}_$i
    let INDEX=${INDEX}+1
done

आपका जवाब निश्चित रूप से थोड़ा स्पष्टीकरण के लायक है। कृपया stackoverflow.com/help/how-to-answer का संदर्भ लें । टिप्पणियाँ खोज योग्य सामग्री बनाने में मदद करेंगी।
जे। चोमेल

3
हालांकि यह कोड स्निपेट प्रश्न को हल कर सकता है, जिसमें स्पष्टीकरण सहित वास्तव में आपकी पोस्ट की गुणवत्ता में सुधार करने में मदद करता है। याद रखें कि आप भविष्य में पाठकों के लिए प्रश्न का उत्तर दे रहे हैं, और उन लोगों को आपके कोड सुझाव के कारणों का पता नहीं चल सकता है। कृपया अपने कोड को व्याख्यात्मक टिप्पणियों के साथ भीड़ न दें, इससे कोड और स्पष्टीकरण दोनों की पठनीयता कम हो जाती है!
kayess

2

बैश 4 में, आप सहयोगी सरणियों का उपयोग कर सकते हैं:

declare -A foo
foo[0]="bar"
foo[35]="baz"
for key in "${!foo[@]}"
do
    echo "key: $key, value: ${foo[$key]}"
done

# output
# $ key: 0, value bar.
# $ key: 35, value baz.

बैश 3 में, यह काम करता है (zsh में भी काम करता है):

map=( )
map+=("0:bar")
map+=("35:baz")

for keyvalue in "${map[@]}" ; do
    key=${keyvalue%%:*}
    value=${keyvalue#*:}
    echo "key: $key, value $value."
done

1
users=("kamal" "jamal" "rahim" "karim" "sadia")
index=()
t=-1

for i in ${users[@]}; do
  t=$(( t + 1 ))
  if [ $t -eq 0 ]; then
    for j in ${!users[@]}; do
      index[$j]=$j
    done
  fi
  echo "${index[$t]} is $i"
done

1
ये गलत है! इनर लूप बेकार है और गलत परिणामों के लिए ड्राइव कर सकता है!
एफ। होरी

1

डंपिंग एरे के लिए सिंपल वन लाइन ट्रिक

मैंने रिक्त स्थान के साथ एक मान जोड़ा है:

foo=()
foo[12]="bar"
foo[42]="foo bar baz"
foo[35]="baz"

मैं, जल्दी से डंप करने के लिए सरणियों या साहचर्य सरणियों का उपयोग करता हूं

यह एक लाइन कमांड:

paste <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")

प्रस्तुत करेगा:

12  bar
35  baz
42  foo bar baz

व्याख्या की

  • printf "%s\n" "${!foo[@]}"एक न्यूलाइन द्वारा अलग की गई सभी कुंजियों को प्रिंट करेगा ,
  • printf "%s\n" "${foo[@]}"एक नई रेखा द्वारा अलग किए गए सभी मानों को प्रिंट करेगा ,
  • paste <(cmd1) <(cmd2)के उत्पादन cmd1और cmd2लाइन को लाइन से मर्ज करेगा ।

ट्यूनिंग

इससे ट्यून किया जा सकता है -d स्विच :

paste -d : <(printf "%s\n" "${!foo[@]}") <(printf "%s\n" "${foo[@]}")
12:bar
35:baz
42:foo bar baz

या और भी:

paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}")
foo[12]='bar'
foo[35]='baz'
foo[42]='foo bar baz'

सहयोगी सरणी समान काम करेगी:

declare -A bar=([foo]=snoopy [bar]=nice [baz]=cool [foo bar]='Hello world!')
paste -d = <(printf "bar[%s]\n" "${!bar[@]}") <(printf '"%s"\n' "${bar[@]}")
bar[foo bar]="Hello world!"
bar[foo]="snoopy"
bar[bar]="nice"
bar[baz]="cool"

के साथ जारी करें को नई पंक्तियों या विशेष वर्ण

दुर्भाग्य से, कम से कम एक शर्त यह है कि यह काम नहीं करता है: जब चर में नई रेखा नहीं होती है:

foo[17]=$'There is one\nnewline'

कमांड pasteलाइन-दर-लाइन विलय करेगा, इसलिए आउटपुट गलत हो जाएगा:

paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "'%s'\n" "${foo[@]}")
foo[12]='bar'
foo[17]='There is one
foo[35]=newline'
foo[42]='baz'
='foo bar baz'

इस कार्य के लिए, आप दूसरी कमांड के %qबजाय (और व्हिप को उद्धृत कर सकते हैं) का उपयोग कर सकते हैं :%sprintf

paste -d = <(printf "foo[%s]\n" "${!foo[@]}") <(printf "%q\n" "${foo[@]}")

सही प्रस्तुत करना होगा:

foo[12]=bar
foo[17]=$'There is one\nnewline'
foo[35]=baz
foo[42]=foo\ bar\ baz

से man bash:

          %q     causes  printf  to output the corresponding argument in a
                 format that can be reused as shell input.

printf "%q\n" "${var[@]}" न्यूलाइन के लिए मेरा अप वोट मेरी समस्या थी!
तकनीकी
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.