在bash中同时迭代两个数组

131

我有两个数组。

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

我希望同时遍历这两个数组,即对这两个数组的第一个元素执行一条命令,然后对第二个元素执行相同的命令,以此类推。伪代码:

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

我该怎么做呢?


重复的 https://dev59.com/il4b5IYBdhLWcg3wvkA- 包含了一些关于当值对不是两个平行数组时的想法,而是像不同目录中的文件名对之类的东西。 - tripleee
6个回答

156

从anishsane的回答和其中的评论中,我们现在知道了你想要什么。这里是同样的内容,使用for循环以更bash方式呈现。请参阅循环结构部分的参考手册。我还使用printf而不是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

另一种可能性是使用关联数组:

#!/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

根据您想要做什么,您也可以考虑这第二种可能性。但是请注意,您在第二种可能性中不会轻易地控制字段的显示顺序(嗯,它是一个关联数组,所以这并不令人意外)。


4
请不要将变量称为“数组”,无论如何都不要这样做。对回答点赞。 - MrR
有没有一种更易读的数组变量来实现这个?在可读性方面,变量数组和array2是非常糟糕的做法。 - ToiletGuy
2
@ToiletGuy 使用你想要的名称。我重复使用了 OP 使用的名称。 - gniourf_gniourf

56
如果所有的数组都已正确排序,只需传递索引即可。
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

1
有没有一种更易读的数组变量来实现这个?在可读性方面,变量数组和array2都是非常糟糕的做法。如果我只想让数组成为“country”,而array2成为“continent”,怎么办? - ToiletGuy
1
是的,变量名(像所有变量名一样)是任意的。Array和array2之所以被使用,是因为问题是以上面的方式编写的。 - cthomaspdx

25
您需要对数组和数组2进行循环。
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

编辑:不要使用以下基于tr的实现方式。它不适用于包含空格的数组元素。为了保持评论的相关性,不予删除。请参考Glenn Jackman的评论而非下面的回答。

/编辑

另外,你可以使用这个选项(无需循环):

paste <(tr ' ' '\n' <<< ${array[*]}) <(tr ' ' '\n' <<< ${array2[*]}) | sed 's/\t/ is in /'

3
猜测这就是你想要的。 - anishsane
3
避免生成两个tr: paste <(printf "%s\n" "${array[@]}") <(printf "%s\n" "${array2[@]}") | sed 's/\t/ is in /' - glenn jackman

8

针对所提出的问题(包含3个元素的数组):

for i in $(seq 0 2) ; do
  echo "${array1[$i]} is in ${array2[$i]}"
done

2
甚至可以使用 for i in 0 1 2; do ... - ShreevatsaR
2
或者 for i in {0..2}; do - nos

5
如果这两个变量是包含多行文本的字符串,例如:
listA=$(echo -e "Vietnam\nGermany\nArgentina")
listB=$(echo -e "Asia\nEurope\nAmerica")

那么,这种情况的解决方案是:
while read strA <&3 && read strB <&4; do
   echo "$strA is in $strB"
done 3<<<"$listA" 4<<<"$listB"

它们已经在两个数组中,不需要将它们转换为字符串。 - runlevel0

0

我在这里添加答案有两个原因。首先,imo错误地标记为重复(Looping over pairs of values in bash)导致了这里。
其次,尽管情况略有不同,但此答案为该主题增加了一些有价值的知识。

在这个问题中,有两个数组需要迭代,在重复项中只是简单地迭代连接的值,因此迭代值对。

这是我发现有用的从值对数组中迭代值对:

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

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

请注意 set -- e,它只是将越南和亚洲作为第一和第二个参数添加到此情况下的第一次迭代中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接