ZSHでは、どの算術式を配列の添え字として表示できますか?

Dec 22 2020

ZSHマニュアル(zshparam(1))には次のように書かれています。

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 `$((...))'.

ただし、これはすぐに失敗します。

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

質問:なぜ、そして例外は何ですか?

注:この質問は、ランダムな要素にアクセスすることを提案しているdon_crisstiの回答に由来し$arr[RANDOM % $#arr + 1]ていますが、これにより上記のエラーが発生します。

回答

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

技術的には、どの式も下付き文字として表示できます。問題は、パーサーに必要なものを添え字に入れさせることです。スペースを含む一部の文字は、決してそれを作りません。下付き文字は単語の一部であるため、下付き文字の一部にできるのは単語の構成文字のみです。

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

添え字パーサーは最初の無効な文字で停止し、「無効な添え字」エラーは、zshが終了する閉じ括弧をチェックする前にトリガーされます。

mc% echo $arr[ 1  
zsh: invalid subscript

ではecho $arr[ 1]、スペースの後の部分は実際には別の単語と見なされます。解析の失敗のためにzshがコマンドの実行を開始しないことを除いてecho$arr[との展開の結果として2つの引数を受け取ります1]。算術式の一部として考えることが実際にはそのように解析されていないことがわかる場合がいくつかあります。たとえば、次のようになります。

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

もちろん、単語を構成しない文字は、算術式やコマンド置換などのネストされた展開の一部として侵入する可能性があります。

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

パラメータ展開が二重引用符で囲まれている場合、(バランスの取れた閉じ括弧または終了引用符を除く)任意の文字が下付き文字の一部になります。これは、二重引用符で囲まれている場合、どの文字も事実上単語構成文字であるためです。同様に、パラメーター展開で中括弧が使用されている場合、zshは、添え字の}閉じ括弧]を探す前に、パラメーター展開の閉じ括弧を探します。したがって、単語を構成しない文字が添え​​字になります。

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

本質的な詳細に飛び込みたい場合はparse_subscript、関連する関数は、から呼び出されgetindexます。