У меня есть вопрос о расширении параметров bash, внутри выражения с запятой, внутри арифметического выражения. У меня есть два оператора, которые, как я думал, должны быть эквивалентны, но они не эквивалентны.
Почему строка bash
n=3; k=10; echo $((n++,k=$n))
выводится 3
вместо 4
? (Он устанавливается n
в 4
, как я и ожидал, но устанавливается k
в 3
.)
В отличие от этого, строка bash
n=3; k=10; echo $((n++,k=n))
выводит 4
, как я и ожидал. (Он устанавливает n
значение 4
, а также k
значение 4
.)
Я пробовал заменять n++
на ++n
, на n=n+1
и на n=$((n+1))
в обеих строках bash, и все они приводят к одному и тому же несоответствию: k=$n
yields 3
во всех скриптах и k=n
yields 4
во всех из них.
Насколько я понимаю, если значение n
является целым числом (а это так), $n
то и n
должно иметь то же значение внутри арифметического выражения. (И это арифметическое выражение из-за конструкции (( ... ))
.) Согласно руководству по bash, в разделе «Арифметическая оценка», в арифметическом выражении:
Shell variables are allowed as operands; parameter expansion is performed before the
expression is evaluated. Within an expression, shell variables may also be referenced by
name without using the parameter expansion syntax.
Так почему же bash обрабатывает , $n
отлично от , n
в этом примере, и как именно он оценивает $n
?
Мне не удалось воспроизвести проблему без использования оператора запятой. Оператор запятой, насколько я знаю, вычисляет каждое из своих подвыражений-компонентов слева направо, включая все побочные эффекты каждого компонента при вычислении этого компонента. Значением выражения с запятой затем является значение последнего вычисленного компонента (самого правого).
Этот вопрос возник в контексте гораздо более сложного сценария, и в конце концов я сузил его до этого простого примера, демонстрирующего проблему.
Итак, что я неправильно понимаю в арифметическом расширении, расширении параметров или операторе запятой?
Обратите внимание, что я не ищу обходной путь, поскольку он у меня уже есть: версия с n
вместо $n
работает так, как я и ожидал. Я просто хочу понять, что делает bash в версии с $n
, и почему она делает что-то другое, чем версия с просто n
.
решение1
Происходит расширение параметров оболочкидо оценки выражения, включая обработку запятых:
Выражение обрабатывается так, как если бы оно было заключено в двойные кавычки, но двойные кавычки внутри скобок не обрабатываются специально. Все токены в выражении подвергаются расширению параметров и переменных, подстановке команд и удалению кавычек. Результат обрабатывается как арифметическое выражение, которое должно быть оценено.
Вы можете увидеть это с помощью
unset n
echo $((n++,k=$n))
Сообщение об ошибке,
bash: n++,k=: syntax error: operand expected (error token is "=")
показывает, что $n
заменяется до обработки всего арифметического выражения.
В вашем случае вычисляется выражение
n++,k=3
решение2
Внутри $((...))
сначала выполняется расширение¹, как будто внутри двойных кавычек, а затем оценивается результат.
Итак, в n=3; k=10; echo $((n++,k=$n))
(или n=1; echo "$((++n + $n))"
, и это не ограничивается ,
) вычисляется арифметическое выражение n++, k=3
.
Здесь вам необходимо:
n=3; k=10; echo "$((n++,k=n))"
(также обратите внимание на кавычки, так как арифметическое расширение подлежит разделению+глобализации, как и другие формы расширения слов в оболочках POSIX).
¹, вы найдете некоторые вариации, где вызываются массивы и ассоциативные массивы, так как некоторые оболочки будут пытаться $((hash[$key]++))
правильно обрабатывать, когда $key
содержит ]
, например