129

I have two arrays.

array=(
  Vietnam
  Germany
  Argentina
)
array2=(
  Asia
  Europe
  America
)

I want to loop over these two arrays simulataneously, i.e. invoke a command on the first elements of the two arrays, then invoke the same command on the second elements, and so on. Pseudocode:

for c in ${array[*]}
do
  echo -e " $c is in ......"
done

How can I do this?

oguz ismail
  • 1
  • 16
  • 47
  • 69
user2354862
  • 1,291
  • 2
  • 8
  • 3
  • The duplicate https://stackoverflow.com/questions/28725333/looping-over-pairs-of-values-in-bash has some ideas for when the pairs of values are not two parallel arrays, but rather something like pairs of file names in different directories for example. – tripleee Jun 03 '21 at 11:52

6 Answers6

152

From anishsane's answer and the comments therein we now know what you want. Here's the same thing in a bashier style, using a for loop. See the Looping Constructs section in the reference manual. I'm also using printf instead of echo.

#!/bin/bash

array=( "Vietnam" "Germany" "Argentina" )
array2=( "Asia" "Europe" "America" )

for i in "${!array[@]}"; do
    printf "%s is in %s\n" "${array[i]}" "${array2[i]}"
done

Another possibility would be to use an associative array:

#!/bin/bash

declare -A continent

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

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

Depending on what you want to do, you might as well consider this second possibility. But note that you won't easily have control on the order the fields are shown in the second possibility (well, it's an associative array, so it's not really a surprise).

oguz ismail
  • 1
  • 16
  • 47
  • 69
gniourf_gniourf
  • 44,650
  • 9
  • 93
  • 104
56

If all of the arrays are ordered correctly just pass around the index.

array=(
  Vietnam
  Germany
  Argentina
)
array2=(
  Asia
  Europe
  America
)

for index in ${!array[*]}; do 
  echo "${array[$index]} is in ${array2[$index]}"
done

Vietnam is in Asia
Germany is in Europe
Argentina is in America
cthomaspdx
  • 655
  • 5
  • 6
  • 1
    Is there a way to achieve this using a more readable variable of an array? The variable array and array2 are very bad practices to use in terms of readability. What if I just want the array to be `country` and array2 to be `continent` – ToiletGuy Sep 17 '21 at 09:25
  • Yeah, the variable names (like all variable names) are arbitrary. Array And array2 were used because that was how the question was written above. – cthomaspdx Sep 18 '21 at 14:05
25

You need a loop over array & array2

i=0
while [ $i -lt ${#array[*]} ]; do
    echo ${array[$i]} is in ${array2[$i]}
    i=$(( $i + 1));
done

Vietnam is in Asia
Germany is in Europe
Argentina is in America

EDIT: Do not use the below tr based implementation. It will not work for array elements containing spaces. Not removing it so as to keep the comments relevant. See glenn jackman's comment instead of below answer.

/EDIT

Alternately, you can use this option (without loop):

paste <(tr ' ' '\n' <<< ${array[*]}) <(tr ' ' '\n' <<< ${array2[*]}) | sed 's/\t/ is in /'
anishsane
  • 20,270
  • 5
  • 40
  • 73
8

Specifically for the question asked (arrays with 3 items):

for i in $(seq 0 2) ; do
  echo "${array1[$i]} is in ${array2[$i]}"
done
oguz ismail
  • 1
  • 16
  • 47
  • 69
runlevel0
  • 2,715
  • 2
  • 24
  • 31
5

If the two vars were two string with multiple lines, like this:

listA=$(echo -e "Vietnam\nGermany\nArgentina")
listB=$(echo -e "Asia\nEurope\nAmerica")

Then, the solution for this case is:

while read strA <&3 && read strB <&4; do
   echo "$strA is in $strB"
done 3<<<"$listA" 4<<<"$listB"
Fabrício Pereira
  • 1,521
  • 1
  • 12
  • 20
0

I am adding this answer here for two reasons. First, the imo falsly tagged duplicate (Looping over pairs of values in bash) leads here.
Second, although the scenario is slightly different, this answer adds some valuable knowledge to the topic.

In this question here there are two arrays to be iterated over, in the duplicate one there is simply a nested iteration over values that are connected, so an iteration over value pairs.

Here is the iteration over value pairs from an array of value pairs, that I found useful:

PAIRS=("Vietnam Asia" \
"Germany Europe" \
"Argentina America")

for pair in "${PAIRS[@]}"
do
set -- $pair
echo "$1 is in $2"
done

Note the set -- e which just adds eg. Vietnam and Asia as the first and second parameter for in this case the first iteration.

atripes
  • 1,683
  • 4
  • 20
  • 23