Estoy intentando escribir una finalización de bash por primera vez, y estoy un poco confundido acerca de las dos formas de desreferenciar matrices de bash ( ${array[@]}
y ${array[*]}
).
Aquí está el fragmento de código relevante (funciona, por cierto, pero me gustaría entenderlo mejor):
_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} ) )
}
La documentación de bash dice :
Se puede hacer referencia a cualquier elemento de una matriz usando $ {nombre [subíndice]}. Las llaves son necesarias para evitar conflictos con los operadores de expansión de nombre de archivo del shell. Si el subíndice es '@' o '*', la palabra se expande a todos los miembros del nombre de la matriz. Estos subíndices difieren solo cuando la palabra aparece entre comillas dobles. Si la palabra está entre comillas dobles, $ {nombre [*]} se expande a una sola palabra con el valor de cada miembro de la matriz separado por el primer carácter de la variable IFS, y $ {nombre [@]} expande cada elemento del nombre a una palabra separada.
Ahora creo que entiendo que compgen -W
espera una cadena que contenga una lista de palabras de posibles alternativas, pero en este contexto no entiendo qué significa "$ {nombre [@]} expande cada elemento del nombre a una palabra separada".
En pocas palabras: ${array[*]}
funciona; ${array[@]}
no lo hace. Me gustaría saber por qué, y me gustaría entender mejor en qué se ${array[@]}
expande exactamente .
fuente
Tu título pregunta sobre
${array[@]}
versus,${array[*]}
pero luego preguntas sobre$array[*]
versus, lo$array[@]
cual es un poco confuso. Responderé a ambos:Cuando cita una variable de matriz y la usa
@
como subíndice, cada elemento de la matriz se expande a su contenido completo independientemente del espacio en blanco (en realidad, uno de$IFS
) que pueda estar presente dentro de ese contenido. Cuando usa el asterisco (*
) como subíndice (independientemente de si está citado o no), puede expandirse a nuevo contenido creado al dividir el contenido de cada elemento de la matriz en$IFS
.Aquí está el script de ejemplo:
#!/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
Y aquí está su salida:
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'
Yo personalmente suelo querer
"${myarray[@]}"
. Ahora, para responder a la segunda parte de su pregunta,${array[@]}
versus$array[@]
.Citando los documentos de bash, que citó:
$ myarray= $ myarray[0]="one" $ myarray[1]="two" $ echo ${myarray[@]} one two
Pero, cuando lo hace
$myarray[@]
, el signo de dólar está estrechamente vinculado, pormyarray
lo que se evalúa antes que el[@]
. Por ejemplo:$ ls $myarray[@] ls: cannot access one[@]: No such file or directory
Pero, como se indica en la documentación, los corchetes son para la expansión del nombre de archivo, así que intentemos esto:
$ touch one@ $ ls $myarray[@] one@
Ahora podemos ver que la expansión del nombre de archivo ocurrió después de la
$myarray
expansión.Y una nota más,
$myarray
sin un subíndice, se expande al primer valor de la matriz:$ myarray[0]="one four" $ echo $myarray[5] one four[5]
fuente
IFS
afecta la salida de manera diferente según@
vs.*
y cotizado vs. no cotizado.${array[*]}
o${array[@]}
. La falta de frenillos fue simplemente un descuido. Más allá de eso, ¿puede explicar en qué${array[*]}
se expandiría elcompgen
comando? Es decir, en ese contexto, ¿qué significa expandir la matriz en cada uno de sus elementos por separado?${array[@]}
suele ser el camino a seguir. Lo que estoy tratando de entender es por qué en este caso solo${array[*]}
funciona.