Welche arithmetischen Ausdrücke können in ZSH als Array-Index angezeigt werden?

Dec 22 2020

Das ZSH-Handbuch ( zshparam(1)) lautet:

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

Dies schlägt jedoch schnell fehl:

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

Frage: Warum und was sind die Ausnahmen?

Hinweis: Diese Frage stammt aus der Antwort von don_crissti , in der vorgeschlagen wird $arr[RANDOM % $#arr + 1], auf ein zufälliges Element zuzugreifen. Dies führt jedoch zu dem oben genannten Fehler.

Antworten

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

Technisch gesehen kann jeder Ausdruck als Index erscheinen. Das Problem besteht darin, dass der Parser das, was Sie wollen, in den Index einfügt. Einige Zeichen, einschließlich Leerzeichen, schaffen es nie. Nur Wortbestandteile können Teil des Index sein, da der Index Teil eines Wortes ist.

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

Der Index-Parser stoppt beim ersten ungültigen Zeichen, und der Fehler "ungültiger Index" wird ausgelöst, bevor zsh überhaupt nach der abschließenden Klammer zum Schließen sucht.

mc% echo $arr[ 1  
zsh: invalid subscript

In echo $arr[ 1]wird der Teil nach dem Leerzeichen tatsächlich als separates Wort betrachtet: echowürde zwei Argumente erhalten, die sich aus der Erweiterung von $arr[und ergeben 1], mit der Ausnahme, dass zsh aufgrund des Analysefehlers keinen Befehl ausführt. Es gibt einige Fälle, in denen Sie feststellen können, dass das, was Sie als Teil des arithmetischen Ausdrucks betrachten, tatsächlich nicht als solches analysiert wird, zum Beispiel:

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

Zeichen, die keine Wörter enthalten, können sich natürlich als Teil einer verschachtelten Erweiterung wie eines arithmetischen Ausdrucks oder einer Befehlssubstitution einschleichen.

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

Wenn die Parametererweiterung in doppelte Anführungszeichen steht, wird jedes Zeichen (mit Ausnahme einer ausgeglichenen schließenden Klammer oder eines Endanführungszeichens) als Teil des Index durchlaufen. Das liegt daran, dass in doppelten Anführungszeichen jedes Zeichen effektiv ein Wortbestandteil ist. Wenn für die Parametererweiterung geschweifte Klammern verwendet werden, sucht zsh nach der schließenden Klammer }für die Parametererweiterung, bevor nach der schließenden Klammer ]für den Index gesucht wird, sodass Zeichen, die keine Wörter enthalten, in den Index gelangen.

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

Wenn Sie in die Details eintauchen möchten, wird die entsprechende Funktion von parse_subscriptaufgerufen getindex.