Po raz pierwszy próbuję napisać zakończenie basha i jestem trochę zdezorientowany co do dwóch sposobów dereferencji tablic bash ( ${array[@]}
i ${array[*]}
).
Oto odpowiedni fragment kodu (nawiasem mówiąc, działa, ale chciałbym to lepiej zrozumieć):
_switch()
{
local cur perls
local ROOT=${PERLBREW_ROOT:-$HOME/perl5/perlbrew}
COMPREPLY=()
cur=${COMP_WORDS[COMP_CWORD]}
perls=($ROOT/perls/perl-*)
# remove all but the final part of the name
perls=(${perls[*]##*/})
COMPREPLY=( $( compgen -W "${perls[*]} /usr/bin/perl" -- ${cur} ) )
}
dokumentacja basha mówi :
Do każdego elementu tablicy można się odwołać za pomocą $ {nazwa [wskaźnik]}. Nawiasy są wymagane, aby uniknąć konfliktów z operatorami rozwijania nazw plików w powłoce. Jeśli indeksem dolnym jest „@” lub „*”, słowo jest interpretowane na wszystkie elementy nazwy tablicy. Te indeksy różnią się tylko wtedy, gdy słowo występuje w cudzysłowie. Jeśli słowo jest umieszczone w cudzysłowie, $ {name [*]} rozwija się do pojedynczego słowa z wartością każdego elementu tablicy oddzieloną pierwszym znakiem zmiennej IFS, a $ {name [@]} rozszerza każdy element nazwy do osobnego słowa.
Teraz myślę, że rozumiem, że compgen -W
oczekuje łańcucha zawierającego listę słów z możliwymi alternatywami, ale w tym kontekście nie rozumiem, co oznacza „$ {nazwa [@]} rozszerza każdy element nazwy do osobnego słowa”.
Krótko mówiąc: ${array[*]}
prace; ${array[@]}
nie. Chciałbym wiedzieć dlaczego i chciałbym lepiej zrozumieć, co dokładnie się ${array[@]}
rozszerza.
źródło
Twój tytuł pyta o
${array[@]}
versus,${array[*]}
ale potem pytasz o$array[*]
versus,$array[@]
co jest nieco zagmatwane. Odpowiem zarówno:Kiedy cytujesz zmienną tablicową i używasz jej
@
jako indeksu dolnego, każdy element tablicy jest rozszerzany do pełnej zawartości, niezależnie od białych znaków (a właściwie jednej$IFS
), która może znajdować się w tej treści. Gdy używasz gwiazdki (*
) jako indeksu dolnego (niezależnie od tego, czy jest ona cytowana, czy nie), może ona rozwinąć się do nowej zawartości utworzonej przez rozbicie zawartości każdego elementu tablicy w$IFS
.Oto przykładowy skrypt:
#!/bin/sh myarray[0]="one" myarray[1]="two" myarray[3]="three four" echo "with quotes around myarray[*]" for x in "${myarray[*]}"; do echo "ARG[*]: '$x'" done echo "with quotes around myarray[@]" for x in "${myarray[@]}"; do echo "ARG[@]: '$x'" done echo "without quotes around myarray[*]" for x in ${myarray[*]}; do echo "ARG[*]: '$x'" done echo "without quotes around myarray[@]" for x in ${myarray[@]}; do echo "ARG[@]: '$x'" done
A oto wynik:
with quotes around myarray[*] ARG[*]: 'one two three four' with quotes around myarray[@] ARG[@]: 'one' ARG[@]: 'two' ARG[@]: 'three four' without quotes around myarray[*] ARG[*]: 'one' ARG[*]: 'two' ARG[*]: 'three' ARG[*]: 'four' without quotes around myarray[@] ARG[@]: 'one' ARG[@]: 'two' ARG[@]: 'three' ARG[@]: 'four'
Osobiście zwykle tego chcę
"${myarray[@]}"
. Teraz, aby odpowiedzieć na drugą część twojego pytania, w${array[@]}
porównaniu$array[@]
.Cytując dokumenty bash, które zacytowałeś:
$ myarray= $ myarray[0]="one" $ myarray[1]="two" $ echo ${myarray[@]} one two
Ale kiedy to zrobisz
$myarray[@]
, znak dolara jest ściśle powiązany,myarray
więc jest oceniany przed[@]
. Na przykład:$ ls $myarray[@] ls: cannot access one[@]: No such file or directory
Ale, jak zauważono w dokumentacji, nawiasy służą do rozwijania nazw plików, więc spróbujmy tego:
$ touch one@ $ ls $myarray[@] one@
Teraz widzimy, że rozszerzenie nazwy pliku nastąpiło po
$myarray
rozszerzeniu.I jeszcze jedna uwaga,
$myarray
bez indeksu rozwijanego do pierwszej wartości tablicy:$ myarray[0]="one four" $ echo $myarray[5] one four[5]
źródło
IFS
wpływa na wyjście różnie w zależności od@
vs.*
i cytowane vs. cytowane.${array[*]}
lub${array[@]}
. Brak aparatu ortodontycznego był po prostu nieostrożnością. Poza tym, czy możesz wyjaśnić, co${array[*]}
rozszerzyłoby się wcompgen
poleceniu? To znaczy, co w tym kontekście oznacza rozszerzenie tablicy na każdy z jej elementów oddzielnie?${array[@]}
jest to zwykle droga. Próbuję zrozumieć, dlaczego w tym przypadku tylko${array[*]}
działa.