Ітераціюйте над двома масивами одночасно в bash


80

У мене два масиви.

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

Я хочу виконати цикл по цих двох масивах одночасно, тобто викликати команду для перших елементів двох масивів, потім викликати ту саму команду для других елементів тощо. Псевдокод:

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

Як я можу це зробити?

Відповіді:


98

З відповіді anishsane та коментарів до них ми тепер знаємо, чого ви хочете. Ось те саме в стилі башер , використовуючи цикл for. Див. Розділ “ Циклічні конструкції ” в довідковому посібнику . Я також використовую 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

Залежно від того, що ви хочете зробити, ви можете також розглянути цю другу можливість. Але зауважте, що ви не зможете легко контролювати порядок, коли поля відображаються при другій можливості (ну, це асоціативний масив, тому насправді це не сюрприз).


43

Якщо всі масиви впорядковані правильно, просто обведіть індекс.

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

18

Вам потрібен цикл над масивом & 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: Не використовуйте наведену нижче trреалізацію. Це не буде працювати для елементів масиву, що містять пробіли. Не видаляючи його, щоб зберегти відповідні коментарі. Дивіться коментар Глена Джекмана замість відповіді нижче.

/ РЕДАКТУВАТИ

Крім того, ви можете використовувати цю опцію (без циклу):

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

3
Я ЗДУВАЮ, це те, що ти хочеш.
anishsane

@ user2354862 Якщо так, прийміть відповідь .
Ansgar Wiechers

3
або уникайте нересту tr двічі:paste <(printf "%s\n" "${array[@]}") <(printf "%s\n" "${array2[@]}") | sed 's/\t/ is in /'
glenn jackman

4

Якщо два варіанта були двома рядками з кількома рядками, ось так:

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

2

Зокрема для заданого питання (масиви з 3 елементами):

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


0
#!/bin/bash

read -p "Enter File name : " file

read -ra USERS <<< $(cut -d: -f1 ${file})
read -ra DIRS <<< $(cut -d: -f6 ${file})


if [ ${#USERS[@]} == ${#DIRS[@]} ]
then

echo "Same size arrays.."

THRO=$(expr ${#USERS[@]} - 1)

for i in `seq 0 ${THRO}`
do
useradd -G sftp_users -d /home/sftp${DIRS[$i]} -s /sbin/nologin ${USERS[$i]}
done


else

echo "need same size arrays.."

fi

Для мене щось подібне спрацювало. Я намагався створити декількох користувачів із файлу / etc / passwd іншого сервера. Не загальне рішення, але виконало свою мету.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.