Bash: арифметическое расширение, расширение параметров и оператор запятой

Bash: арифметическое расширение, расширение параметров и оператор запятой

У меня есть вопрос о расширении параметров 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=$nyields 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содержит ], например

Связанный контент