синтаксис цикла for

синтаксис цикла for

Почему

for i in {1..5}; do x="${i}" echo "$x"; done

не выводится

1
2
3
4
5

?

Как правильно это сделать?

(Проверено)for i in {1..5}; do x=$(i) echo "$x"; done

-bash: i: команда не найдена

и другие)

решение1

Отвечаю на ваш вопрос так, как он был задан

Почему for i in {1..5}; do x="${i}" echo "$x"; doneне выводится 1, 2, 3, 4, 5?

Причина в порядке, в котором операции оцениваются во время выполнения. Посмотрите на эту команду

x="${i}" echo "$x"

Что это делает?

  1. Заменить переменные их значениями
  2. Присвоить переменной временное значениеx
  3. Выполнить команду

Итак, вы получаете

  1. x=1 echo ""(или x=2 echo ""и т.д.)
  2. На время выполнения этой команды xустанавливается значение1
  3. Команда выполняется:echo ""

Вероятно, вы имели в виду, что эта команда должна состоять из двух инструкций: присвоить значение x, вывести его значение. Но в синтаксисе оболочки то, что вы написали, было совершенно допустимым кодом, поэтому оболочка выполнила его без возражений.

решение2

Вы просили ответить на два вопроса:

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

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

Глядя на ваш код, я вижу два вероятных объяснения того, почему вы написали код именно так:

  1. Может возникнуть небольшая путаница по поводусинтаксис цикла for.

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

синтаксис цикла for

В первом случае я бы сказал, что вы пропустили точку с запятой после назначения переменной. Если вы хотите написать цикл for в одну строку, то вам нужно поставить точку с запятой после каждой команды в теле цикла. Попробуйте это вместо этого:

for i in {1..5}; do x="${i}"; echo "$x"; done

Другой альтернативой было бы написать цикл for, используя многострочный синтаксис с символами новой строки вместо точек с запятой:

for i in {1..5}
do
x="${i}"
echo "${x}"
done

Вы также можете комбинировать точки с запятой и символы новой строки, например:

for i in {1..5}; do
x="${i}"; echo "${x}"
done

оценка простых команд

Во втором случае я бы сказал, что вы, вероятно, предположили, что назначение переменной в прологе команды (т. е. назначение x="$i") происходит до расширения переменной в теле команды (т. е. расширения в ${x}) echo "${x}". Но на самом деле это не так. Чтобы убедиться в этом, мы можем обратиться к странице напростое расширение командыв руководстве Bash или вподраздел о простых командахвСпецификация Posix. Обе эти ссылки включают следующий отрывок:

«Простая команда» — это последовательность необязательных назначений переменных и перенаправлений в любой последовательности, за которой могут следовать слова и перенаправления, завершаемая оператором управления.

Когда требуется выполнить заданную простую команду (то есть, когда любая условная конструкция, такая как список И-ИЛИ илислучайоператор не обошел простую команду), то следующие расширения, назначения и перенаправления должны быть выполнены от начала текста команды до конца:

  1. Слова, которые распознаются как переменные назначения или перенаправления в соответствии сПравила грамматики Shellсохраняются для обработки на шагах 3 и 4.

  2. Слова, которые не являются переменными назначениями или перенаправлениями, должны быть расширены. Если после их расширения остаются какие-либо поля, первое поле должно считаться именем команды, а остальные поля — аргументами для команды.

  3. Перенаправления должны выполняться, как описано вПеренаправление.

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

Обратите внимание, что шаг 2 — это место, где происходит расширение переменной в команде, но шаг 1 говорит нам, что назначения переменных сохраняются до шагов 3 и 4. Из этого следует, что выражение echo "${x}"расширяется до echo ""того, как происходит назначение x="${i}". Это объясняет, почему вы получали пустой вывод.

Для дальнейшего обсуждения этой темы смотрите следующие посты:

решение3

В zsh, используя третью ${var::=value}форму операторов Борна ${var=value}, ${var:=value}где присваивание является безусловным (в отличие от присваивания только в случае, если var не задана/пуста).

for i in {1..5}; do echo ${x::=$i}; done

Или:

for i ({1..5}) echo ${x::=$i}

В bash:

set -o posix # so the value of x remains after eval returns
for i in {1..5}; do x=$i eval 'echo "$x"'; done

То есть, вам необходимо $xбыть настроенным на момент оценки кода, содержащего его расширение.

Для десятичных целых значений, как здесь, вы также можете сделать:

for i in {1..5}; do echo "$((x = i))"; done

Или вы всегда можете использовать ${var:=value}оператор Bourne, установив xпустую строку.

for i in {1..5}; do x=; echo "${x:=$i}"; done

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