数组索引中的算术扩展 - 是否需要美元符号?

Arithmetic expansion in array indices - is the dollar sign needed?

当我在 bash 中的数组索引中使用算术扩展时,像这样:

declare -a FILES
declare -i INDEX=0

for FILE in ./*
do
    FILES[((INDEX++))]="$FILE"
done

我需要在 ((...)) 前面加一个美元符号吗?
那么它是否必须是:

FILES[((INDEX++))]="$FILE"

或者更确切地说:

FILES[$((INDEX++))]="$FILE"

?

在我的 bash 本地副本中,这两种变体似乎都有效 - 它的版本是 4.3.30。

我希望只有后者可以工作,因为我认为只有那个 returns 是算术表达式的结果。但是那里: Bash - arithmetic in array index 我读到只有第一个可能适用于旧版本的 bash (?)。那么究竟哪一个是正确的呢?为什么第一个有效?我还没有找到具体的答案。

美元符号在某些情况下是必需的,但在其他情况下则不需要:

$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

$ echo ((1+2))
bash: syntax error near unexpected token `('

$ echo $((1+2))
3

$ for ((x=0; x<3;++x)); do echo $x; done
0
1
2

$ for $((x=0; x<3;++x)); do echo $x; done
bash: `$((x=0; x<3;++x))': not a valid identifier

阅读 bash 手册页后,compound commands 中不需要美元符号:

Compound commands are the shell programming constructs. Each construct begins with a reserved word or control operator and is terminated by a corresponding reserved word or operator. Any redirections (see Redirections) associated with a compound command apply to all commands within that compound command unless explicitly overridden.

In most cases a list of commands in a compound command’s description may be separated from the rest of the command by one or more newlines, and may be followed by a newline in place of a semicolon.

Bash provides looping constructs, conditional commands, and mechanisms to group commands and execute them as a unit.

for (( expr1 ; expr2 ; expr3 )) 是一个复合命令,因此不需要美元符号来启用算术计算.

echo $((expr)) 不是 复合命令 因为它不是以保留的 bash 关键字开头,所以它需要美元符号才能启用 算术求值.

在数组中,bash 将 [] 之间的表达式视为算术。于是

i=2 ; f[i++]=10

完美。写作 f[((i++))] 也是正确的,但在这种情况下,(()) 不被视为算术扩展运算符,而是被视为嵌套的括号。

注意((expr))计算expr,如果为真则成功,而$((expr))作为其值展开。所以f[$((i++))]也是对的

最后,f[$i++] 不是您想要的,因为 $i 首先展开。例如,i=j ; f[$i++] 将扩展为 f[j++]

备注:一个奇怪的特性是bash在没有$符号的情况下在算术模式下会展开所有:

$ unset i j k f
$ i=j ; j=k ; k=5 ; f[i++]=10
$ declare -p i j k f
declare -- i="6"
declare -- j="k"
declare -- k="5"
declare -a f='([5]="10")'