Acessando variável de índice de matriz do loop de script do shell bash?

18

Eu quero acessar a variável de índice da matriz durante um loop através de uma matriz no meu script de shell bash.

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

O resultado do script acima é:

foo
bar
baz
bat

O resultado que procuro é:

0
1
2
3

Como altero meu script para conseguir isso?

Mowzer
fonte
6
Observe também que você basicamente nunca deseja, em "${array[*]}"vez de "${array[@]}". Usar em *vez de @mais ou menos trata-o como uma sequência em vez de uma matriz.
Jordanm 23/04

Respostas:

23

Você pode fazer isso usando a Lista de chaves da matriz . Na bashpágina do manual:

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

Lista de chaves de matriz . Se nome é uma variável de matriz, expande para a lista de índices de matriz (chaves) atribuídos no nome. Se nome não for uma matriz, expande para 0se o nome estiver definido e nulo caso contrário. Quando @é usada e a expansão aparece entre aspas duplas, cada tecla se expande para uma palavra separada.

Para o seu exemplo:

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

Isto resulta em:

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

Observe que isso também funciona para índices não sucessivos:

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

Isto resulta em:

${AR[3]}=foo
${AR[5]}=bar
${AR[7]}=bat
${AR[25]}=baz
jordanm
fonte
1
Embora essa resposta atinja o resultado desejado, ela é desnecessariamente ofuscada pela instrução printf. Por exemplo: printf "$i=(${AR[i]})\n"ou echo "$i=(${ARi]})"ambos dão um pouco mais, mostrando como obter key & var, mas, estritamente falando echo "$i", teria respondido ao OP. O resto é "fu bash" :)
dimmech
6

Além da resposta de jordanm, você também pode fazer um Cloop semelhante em bash:

for ((idx=0; idx<${#array[@]}; ++idx)); do
    echo "$idx" "${array[idx]}"
done
pfnuesel
fonte
1

você pode fazer algo assim:

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

resultado:

0
1
2
3
F.9876
fonte
1
O que isso diz que  a resposta de pfnuesel   ainda não diz?
G-Man diz 'Restabelecer Monica
Posso estar enganado, mas o pfnuesels responde não reavalia o comprimento do array em cada iteração?
Chris