Saya mencoba menulis penyelesaian bash untuk pertama kalinya, dan saya agak bingung tentang dua cara dereferensi bash array ( ${array[@]}
dan ${array[*]}
).
Berikut potongan kode yang relevan (ngomong-ngomong, berfungsi, tetapi saya ingin memahaminya dengan lebih baik):
_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} ) )
}
Dokumentasi bash mengatakan :
Setiap elemen dari sebuah array dapat direferensikan menggunakan $ {name [subscript]}. Kawat gigi diperlukan untuk menghindari konflik dengan operator perluasan nama file shell. Jika subskripnya adalah '@' atau '*', kata tersebut akan meluas ke semua anggota nama array. Subskrip ini hanya berbeda jika kata tersebut muncul dalam tanda kutip ganda. Jika kata tersebut dikutip ganda, $ {name [*]} diperluas menjadi satu kata dengan nilai setiap anggota array dipisahkan oleh karakter pertama variabel IFS, dan $ {name [@]} memperluas setiap elemen nama ke kata terpisah.
Sekarang saya pikir saya mengerti bahwa compgen -W
mengharapkan string yang berisi daftar kata dari kemungkinan alternatif, tetapi dalam konteks ini saya tidak mengerti apa arti "$ {name [@]} memperluas setiap elemen nama menjadi kata terpisah".
Singkat cerita: ${array[*]}
karya; ${array[@]}
tidak. Saya ingin tahu alasannya, dan saya ingin lebih memahami apa sebenarnya ${array[@]}
perluasan itu.
sumber
Judul Anda bertanya tentang
${array[@]}
versus${array[*]}
tetapi kemudian Anda bertanya tentang$array[*]
versus$array[@]
yang agak membingungkan. Saya akan menjawab keduanya:Saat Anda mengutip variabel array dan menggunakannya
@
sebagai subskrip, setiap elemen array akan diperluas ke konten penuhnya terlepas dari spasi (sebenarnya, salah satu$IFS
) yang mungkin ada di dalam konten itu. Saat Anda menggunakan tanda bintang (*
) sebagai subskrip (terlepas dari apakah itu dikutip atau tidak), itu mungkin meluas ke konten baru yang dibuat dengan memecah setiap konten elemen array di$IFS
.Berikut contoh skripnya:
#!/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
Dan inilah hasilnya:
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'
Saya pribadi biasanya mau
"${myarray[@]}"
. Sekarang, untuk menjawab bagian kedua dari pertanyaan Anda,${array[@]}
versus$array[@]
.Mengutip dokumen bash, yang Anda kutip:
$ myarray= $ myarray[0]="one" $ myarray[1]="two" $ echo ${myarray[@]} one two
Tapi, ketika Anda melakukannya
$myarray[@]
, tanda dolar terikat eratmyarray
sehingga dievaluasi sebelum[@]
. Sebagai contoh:$ ls $myarray[@] ls: cannot access one[@]: No such file or directory
Tapi, seperti yang dicatat dalam dokumentasi, tanda kurung untuk perluasan nama file, jadi mari kita coba ini:
$ touch one@ $ ls $myarray[@] one@
Sekarang kita dapat melihat bahwa perluasan nama file terjadi setelah
$myarray
perluasan.Dan satu catatan lagi,
$myarray
tanpa subskrip akan meluas ke nilai pertama dari array:$ myarray[0]="one four" $ echo $myarray[5] one four[5]
sumber
IFS
mempengaruhi keluaran secara berbeda tergantung pada@
vs.*
dan dikutip vs. tidak dikutip.${array[*]}
atau${array[@]}
. Kurangnya kawat gigi hanyalah kecerobohan. Selain itu, dapatkah Anda menjelaskan apa yang${array[*]}
akan diperluas dalamcompgen
perintah? Artinya, dalam konteks itu apa yang dimaksud dengan memperluas array ke dalam setiap elemennya secara terpisah?${array[@]}
biasanya itulah cara yang harus ditempuh. Apa yang saya coba pahami adalah mengapa dalam kasus ini hanya${array[*]}
berhasil.