Я впервые пытаюсь написать завершение bash, и меня немного смущают два способа разыменования массивов bash ( ${array[@]}
и ${array[*]}
).
Вот соответствующий фрагмент кода (кстати, он работает, но я хотел бы понять его лучше):
_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} ) )
}
В документации bash говорится :
На любой элемент массива можно ссылаться с помощью $ {name [subscript]}. Скобки необходимы, чтобы избежать конфликтов с операторами расширения имени файла оболочки. Если нижний индекс - «@» или «*», слово расширяется до всех членов имени массива. Эти индексы различаются только в том случае, если слово заключено в двойные кавычки. Если слово заключено в двойные кавычки, $ {name [*]} заменяется одним словом со значением каждого члена массива, разделенным первым символом переменной IFS, а $ {name [@]} раскрывает каждый элемент имени к отдельному слову.
Теперь я думаю, что понимаю, что compgen -W
ожидает строку, содержащую список возможных альтернатив, но в этом контексте я не понимаю, что означает «$ {name [@]} расширяет каждый элемент имени до отдельного слова».
Короче говоря: ${array[*]}
работает; ${array[@]}
нет. Я хотел бы знать почему, и я хотел бы лучше понять, во что именно ${array[@]}
расширяется.
источник
Ваш заголовок спрашивает о
${array[@]}
сравнении,${array[*]}
но затем вы спрашиваете о$array[*]
сравнении,$array[@]
что немного сбивает с толку. Я отвечу на оба:Когда вы заключаете переменную массива в кавычки и используете ее
@
в качестве нижнего индекса, каждый элемент массива расширяется до своего полного содержимого независимо от пробелов (фактически, одного из$IFS
), которые могут присутствовать в этом содержимом. Когда вы используете звездочку (*
) в качестве подстрочного индекса (независимо от того, цитируется он или нет), он может расширяться до нового содержимого, созданного путем разбиения содержимого каждого элемента массива на$IFS
.Вот пример сценария:
#!/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
И вот результат:
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'
Я лично обычно хочу
"${myarray[@]}"
. Теперь, чтобы ответить на вторую часть вашего вопроса, по${array[@]}
сравнению с$array[@]
.Цитируя документы bash, которые вы цитировали:
$ myarray= $ myarray[0]="one" $ myarray[1]="two" $ echo ${myarray[@]} one two
Но когда вы это сделаете
$myarray[@]
, знак доллара будет жестко привязан к нему,myarray
поэтому он оценивается перед знаком[@]
. Например:$ ls $myarray[@] ls: cannot access one[@]: No such file or directory
Но, как указано в документации, скобки предназначены для расширения имени файла, поэтому давайте попробуем следующее:
$ touch one@ $ ls $myarray[@] one@
Теперь мы видим, что расширение имени файла произошло после
$myarray
расширения.И еще одно примечание,
$myarray
без нижнего индекса расширяется до первого значения массива:$ myarray[0]="one four" $ echo $myarray[5] one four[5]
источник
IFS
влияет на выходе по- разному в зависимости от@
VS.*
и цитировал против неупомянуты.${array[*]}
или${array[@]}
. Отсутствие подтяжек было просто небрежностью. Помимо этого, можете ли вы объяснить, что${array[*]}
будет расширяться вcompgen
команде? То есть в этом контексте, что означает расширение массива на каждый из его элементов отдельно?${array[@]}
обычно это правильный путь. То , что я пытаюсь понять, почему в этом случае только${array[*]}
работает.