Допустим, мы создаем динамически именованную переменную в zsh
, например:
name="hello"
typeset $name=42
echo ${(P)${name}} # Prints the variable $hello, which is 42
Теперь предположим, что кто-то хочет увеличить или изменить указанную переменную, но не знает ее прямого имени, т.е. я ожидаю, что сработает что-то вроде следующего:
(( ${(P)${name}} = ${(P)${name}} + 1 )) # Set $hello to 43?
Вышеизложенное не работает. Что же сработает?
решение1
$ name=hello
$ hello=42
$ (($name++))
$ echo $hello
43
Как и в любой оболочке типа Korn. Или POSIXly:
$ name=hello
$ hello=42
$ : "$(($name += 1))"
$ echo "$hello"
43
Дело в том, что все расширения параметров, подстановки команд и арифметические расширения выполняются внутри арифметических выражений до того, как арифметическое выражение будет оценено.
((something))
похож на
let "something"
Итак, в (($name++))
(подобно let "$name++"
) это сначала расширяется до hello++
и это оценивается как ++
оператор, примененный к hello
переменной.
В POSIX sh
нет ((...))
оператора, но есть $((...))
арифметикарасширениеоператор. Он не имеет ++
(хотя позволяет реализациям иметь его в качестве расширения вместо того, чтобы требовать, чтобы он был комбинацией унарных и/или бинарных +
операторов), но имеет +=
.
Используя команду : "$((...))"
where :
is the null, мы получаем нечто похожее на ksh's ((...))
. Хотя строгим эквивалентом было бы [ "$((...))" -ne 0 ]
, поскольку ((expression))
возвращает false, когда выражение разрешается в 0.
решение2
Похоже, это сработает:
typeset $name=$(( ${(P)${name}} + 1 ))
Любые альтернативные методы будут высоко оценены.