Доступ к переменной индекса массива из цикла сценария bash?

19

Я хочу получить доступ к переменной индекса массива во время цикла по массиву в моем сценарии оболочки bash.

myscript.sh
#!/bin/bash
AR=('foo' 'bar' 'baz' 'bat')
for i in ${AR[*]}; do
  echo $i
done

Результат приведенного выше сценария:

foo
bar
baz
bat

Результат, который я ищу:

0
1
2
3

Как мне изменить мой сценарий, чтобы добиться этого?

Mowzer
источник
7
Также обратите внимание, что вы в принципе никогда не хотите "${array[*]}"вместо "${array[@]}". Использование *вместо @более или менее обрабатывает его как строку вместо массива.
Иордания

Ответы:

27

Вы можете сделать это, используя Список ключей массива . Со bashстраницы руководства :

${!name[@]}
${!name[*]}

Список ключей массива . Если имя является переменной массива, расширяется до списка индексов (ключей) массива, назначенных в имени. Если имя не является массивом, расширяется до, 0если имя установлено, и ноль в противном случае. Когда @используется и расширение отображается в двойных кавычках, каждый ключ раскрывается в отдельное слово.

Для вашего примера:

#!/bin/bash
AR=('foo' 'bar' 'baz' 'bat')
for i in "${!AR[@]}"; do
  printf '${AR[%s]}=%s\n' "$i" "${AR[i]}"
done

Это приводит к:

${AR[0]}=foo
${AR[1]}=bar
${AR[2]}=baz
${AR[3]}=bat

Обратите внимание, что это также работает для непоследовательных индексов:

#!/bin/bash
AR=([3]='foo' [5]='bar' [25]='baz' [7]='bat')
for i in "${!AR[@]}"; do
  printf '${AR[%s]}=%s\n' "$i" "${AR[i]}"
done

Это приводит к:

${AR[3]}=foo
${AR[5]}=bar
${AR[7]}=bat
${AR[25]}=baz
jordanm
источник
1
Хотя этот ответ достигает желаемого результата, он излишне запутывается оператором printf. Например: printf "$i=(${AR[i]})\n"или echo "$i=(${ARi]})"оба дают немного больше, показывая, как получить key & var, но, строго говоря echo "$i", ответили бы на OP. Остальное "баш фу" :)
dimmech
5

В дополнение к ответу Джорданма вы также можете выполнить Cцикл « Мне нравится» в bash:

for ((idx=0; idx<${#array[@]}; ++idx)); do
    echo "$idx" "${array[idx]}"
done
pfnuesel
источник
1

Вы можете сделать что-то вроде этого:

#!/bin/bash
AR=('foo' 'bar' 'baz' 'bat')
length=${#AR[@]}
for (( i = 0; i < length; i++ )); do
  echo "$i"
done

выход:

0
1
2
3
F.9876
источник
1
Что это говорит о  том, что ответ pfnuesel   еще не говорит?
G-Man говорит: «Восстановите Монику»
Я могу ошибаться, но ответ pfnuesels не переоценивает длину массива на каждой итерации?
Крис