অ্যারেগুলি লুপিং, সূচি এবং মান উভয় মুদ্রণ


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
গুরুত্বপূর্ণ দ্রষ্টব্য, পুনরাবৃত্ত হওয়ার সময় শব্দের একটি স্পেস বিভাজিত তালিকা কোনও অ্যারে নয় is এটিকে (a b c)অ্যারেতে রূপান্তর করতে এটি এমনভাবে মুড়িয়ে রাখুন ।
ব্রিডলি

4
[@]এবং ডাবল উদ্ধৃতি ব্যবহারের অর্থ এটি "শব্দের স্থান দ্বারা পৃথক তালিকা" নয়। স্বতন্ত্র অ্যারে কীগুলির তালিকা আপনি পান, এমনকি স্বতন্ত্র কীগুলিতে শ্বেত স্পেস থাকে।
গ্লেন জ্যাকম্যান

@glennjackman আপনি এই আরও ব্যাখ্যা করতে পারেনThe use of [@] and double quotes means it's not a "space separated list of words"
Kasun Siyambalapitiya

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++))আধুনিক
বাশে

পোস্ট-ইনক্রিমেন্ট কেন? আপনি কেবল মান
বাড়ানো

3
না, "সবসময়" নয়। একটি হ্যাশের "ছিদ্র" থাকতে পারে যার অর্থ সমস্ত সংখ্যা একটি সূচক নয়। আপনার উদাহরণে $ {ITER always সর্বদা $ {I of এর সূচক হয় না}
মার্কো

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

আপনার উত্তর অবশ্যই একটি সামান্য ব্যাখ্যা মূল্যবান। দয়া করে স্ট্যাকওভারফ্লো . com/help/how- to- answer দেখুন । মন্তব্যগুলি অনুসন্ধানযোগ্য সামগ্রী তৈরি করতে সহায়তা করবে।
জে ছোমেল

3
যদিও এই কোড স্নিপেট একটি ব্যাখ্যা সহ প্রশ্নটি সমাধান করতে পারে, সত্যিই আপনার পোস্টের মান উন্নত করতে সহায়তা করে। মনে রাখবেন যে আপনি ভবিষ্যতে পাঠকদের জন্য প্রশ্নের উত্তর দিচ্ছেন, এবং সেই লোকেরা আপনার কোড পরামর্শের কারণগুলি জানেন না। আপনার কোডটি ব্যাখ্যামূলক মন্তব্যে ভিড় না করার চেষ্টা করুন, এটি কোড এবং ব্যাখ্যা উভয়ের পাঠযোগ্যতা হ্রাস করে!
কেয়েস

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[@]}" নতুন লাইনের জন্য আমার আপ ভোট আমার সমস্যা ছিল!
টেকনো
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.