Dostęp do zmiennej indeksu tablicowego z pętli skryptu powłoki bash?

19

Chcę uzyskać dostęp do zmiennej indeksu tablicy podczas zapętlania tablicy w moim skrypcie powłoki bash.

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

Wynikiem powyższego skryptu jest:

foo
bar
baz
bat

Wynik, którego szukam to:

0
1
2
3

Jak mogę zmienić skrypt, aby to osiągnąć?

Kosiarka
źródło
7
Pamiętaj też, że zasadniczo nigdy nie chcesz "${array[*]}"zamiast "${array[@]}". Używanie *zamiast @mniej więcej traktuje go jako ciąg zamiast tablicy.
jordanm

Odpowiedzi:

27

Możesz to zrobić za pomocą listy kluczy tablicy . Ze strony podręcznika bash:

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

Lista kluczy macierzy . Jeśli nazwa jest zmienną tablicową, rozwija się do listy indeksów tablicowych (kluczy) przypisanych w nazwie. Jeśli nazwa nie jest tablicą, rozwija się, 0jeśli nazwa jest ustawiona, w przeciwnym razie ma wartość NULL. Kiedy @jest używany, a rozwinięcie pojawia się w podwójnych cudzysłowach, każdy klawisz jest interpretowany jako osobne słowo.

Na przykład:

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

To skutkuje:

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

Pamiętaj, że działa to również w przypadku kolejnych indeksów:

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

To skutkuje:

${AR[3]}=foo
${AR[5]}=bar
${AR[7]}=bat
${AR[25]}=baz
Jordan
źródło
1
Chociaż ta odpowiedź osiąga pożądany wynik, niepotrzebnie zaciemnia ją instrukcja printf. Na przykład: printf "$i=(${AR[i]})\n"lub echo "$i=(${ARi]})"oba dają trochę więcej, pokazując, jak zdobyć key & var, ale ściśle mówiąc echo "$i"odpowiedziałby OP. Reszta to „bash fu” :)
dimmech,
5

Oprócz odpowiedzi jordanma możesz również wykonać Cpodobną pętlę w bash:

for ((idx=0; idx<${#array[@]}; ++idx)); do
    echo "$idx" "${array[idx]}"
done
pfnuesel
źródło
1

możesz zrobić coś takiego:

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

wynik:

0
1
2
3
F.9876
źródło
1
Co to znaczy, że  odpowiedź pfnuesela jeszcze   nie mówi?
G-Man mówi „Przywróć Monikę”
Mogę się mylić, ale czy odpowiedź pfnuesela nie ocenia ponownie długości tablicy przy każdej iteracji?
Chris