Di ZSH, ekspresi aritmatika apa yang dapat muncul sebagai subskrip array?

Dec 22 2020

Manual ZSH ( zshparam(1)) berbunyi:

Array Subscripts
       Individual elements of an array may be selected using a subscript.  A
       subscript of the form `[exp]' selects the single element exp, where
       exp is an arithmetic expression which will be subject to arithmetic
       expansion as if it were surrounded by `$((...))'.

Namun, ini dengan cepat gagal:

mc% arr=(a b c d e)     
mc% echo $arr[$#arr] e mc% echo $arr[$(($#arr))]
e
mc% echo $arr[$(($#arr - 1))] d mc% echo $arr[$#arr - 1]  
zsh: invalid subscript

Pertanyaan: Mengapa, dan apa pengecualiannya?

Catatan: pertanyaan ini berasal dari jawaban don_crissti di sana , di mana mereka menyarankan $arr[RANDOM % $#arr + 1]untuk mengakses elemen acak, tetapi ini memunculkan kesalahan di atas.

Jawaban

5 Gilles'SO-stopbeingevil' Dec 23 2020 at 03:45

Secara teknis, ekspresi apa pun bisa muncul sebagai subskrip. Masalahnya adalah membuat parser memasukkan apa yang Anda inginkan ke dalam subskrip. Beberapa karakter, termasuk spasi, tidak pernah berhasil. Hanya karakter penyusun kata yang dapat menjadi bagian dari subskrip, karena subskrip adalah bagian dari sebuah kata.

mc% echo $arr[ 1] zsh: invalid subscript mc% echo $arr[1 ]
zsh: invalid subscript
mc% echo $arr[$#arr - 1]
zsh: invalid subscript
mc% echo $arr[$#arr-1]
d

Pengurai subskrip berhenti pada karakter pertama yang tidak valid, dan kesalahan "subskrip tidak valid" dipicu sebelum zsh bahkan memeriksa kurung tutup penutup.

mc% echo $arr[ 1  
zsh: invalid subscript

Dalam echo $arr[ 1], bagian setelah spasi sebenarnya dianggap sebagai kata terpisah: echoakan menerima dua argumen yang dihasilkan dari perluasan $arr[dan 1], kecuali bahwa zsh tidak mulai menjalankan perintah apa pun karena kegagalan penguraian. Ada beberapa kasus di mana Anda dapat mengetahui bahwa apa yang mungkin Anda anggap sebagai bagian dari ekspresi aritmatika ternyata tidak diurai seperti itu, misalnya:

mc% echo $arr[1<<2]   
heredoc> << is a heredoc operator, not part of the subscript.
heredoc> 2]
zsh: invalid subscript

Karakter non-konstituen-kata tentu saja dapat menyelinap sebagai bagian dari perluasan bersarang seperti ekspresi aritmatika atau substitusi perintah.

mc% echo $arr[$[1&3]] 
a
mc% echo $arr[`echo "1 + 2"`]  
c

Jika perluasan parameter dalam tanda kutip ganda, karakter apa pun (selain tanda kurung tutup yang seimbang atau tanda kutip akhir) akan menjadi bagian dari subskrip. Itu karena di dalam tanda kutip ganda, setiap karakter secara efektif merupakan karakter penyusun kata. Demikian juga, jika perluasan parameter menggunakan tanda kurung kurawal, zsh mencari kurung kurawal tutup }untuk perluasan parameter sebelum mencari kurung tutup ]untuk subskrip, sehingga karakter non-konstituen kata membuatnya menjadi subskrip.

mc% echo "$arr[$#arr - 1]" d mc% echo ${arr[$#arr - 1]}
d

Jika Anda ingin menyelami detailnya, fungsi yang relevan parse_subscriptdipanggil dari getindex.