Баш: арифметическое расширение индексов массива - нужен ли знак доллара?
Когда я использую арифметическое расширение в индексе массива в 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, поэтому для включения арифметической оценки требуется знак доллара.