Баш: арифметическое расширение индексов массива - нужен ли знак доллара?

Когда я использую арифметическое расширение в индексе массива в 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.
Я ожидал бы, что только последний будет работать, потому что я думаю, что только один возвращает результат арифметического выражения. Но есть: Bash - арифметика в индексе массива. Я читал, что только первая может работать со старыми версиями bash (?). Так какой из них на самом деле правильный? И почему работает первый? Я не нашел конкретного ответа на этот вопрос.

2 ответа

Решение

В массивах 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")'

Знак доллара требуется в некоторых контекстах, но не в других:

$ 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 знак доллара не требуется в составных командах:

Составные команды являются конструкциями программирования оболочки. Каждая конструкция начинается с зарезервированного слова или управляющего оператора и заканчивается соответствующим зарезервированным словом или оператором. Любые перенаправления (см. Перенаправления), связанные с составной командой, применяются ко всем командам в этой составной команде, если они явно не переопределены.

В большинстве случаев список команд в описании составной команды может быть отделен от остальной команды одной или несколькими символами новой строки и может сопровождаться символом новой строки вместо точки с запятой.

Bash предоставляет циклические конструкции, условные команды и механизмы для группировки команд и выполнения их как единого целого.

for (( expr1 ; expr2 ; expr3 )) является составной командой и, следовательно, знак доллара не требуется для включения арифметической оценки.

В то время как echo $((expr)) не является составной командой, потому что она не начинается с зарезервированного ключевого слова bash, поэтому для включения арифметической оценки требуется знак доллара.

Другие вопросы по тегам