Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Looping over arrays, printing both index and value

Tags:

bash

People also ask

Can we use loops in arrays?

- [Instructor] When you have values in an array, it is common to want to perform actions on each one of the items. You can use a for loop to iterate through all the items in the array and access each element individually.

How do loops and arrays work together?

The elements in an array are accessed by sequential index numbers ranging from 0 to one less than the size of the array. This indexing scheme lends itself to iterative access or processing driven by a for-loop and using the loop control variable as the array index.

How do you run a loop in an array?

The Basic For Loop JavaScript arrays are zero based, which means the first item is referenced with an index of 0. As you can see the for loop statement uses three expressions: the initialization, the condition, and the final expression. The final expression is executed at the end of each loop execution.

How do you iterate through an array in bash?

There are two ways to iterate over items of array using For loop. The first way is to use the syntax of For loop where the For loop iterates for each element in the array. The second way is to use the For loop that iterates from index=0 to index=array length and access the array element using index in each iteration.


You would find the array keys with "${!foo[@]}" (reference), so:

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

Which means that indices will be in $i while the elements themselves have to be accessed via ${foo[$i]}


you can always use iteration param:

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

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

In bash 4, you can use associative arrays:

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.

In bash 3, this works (also works in zsh):

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

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

Simple one line trick for dumping array

I've added one value with spaces:

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

I, for quickly dump bash arrays or associative arrays I use

This one line command:

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

Will render:

12  bar
35  baz
42  foo bar baz

Explained

  • printf "%s\n" "${!foo[@]}" will print all keys separated by a newline,
  • printf "%s\n" "${foo[@]}" will print all values separated by a newline,
  • paste <(cmd1) <(cmd2) will merge output of cmd1 and cmd2 line by line.

Tunning

This could be tunned by -d switch:

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

or even:

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

Associative array will work same:

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"

Issue with newlines or special chars

Unfortunely, there is at least one condition making this not work anymore: when variable do contain newline:

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

Command paste will merge line-by-line, so output will become wrong:

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'

For this work, you could use %q instead of %s in second printf command (and whipe quoting):

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

Will render perfect:

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

From man bash:

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

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