
Почему
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"
Что это делает?
- Заменить переменные их значениями
- Присвоить переменной временное значение
x
- Выполнить команду
Итак, вы получаете
x=1 echo ""
(илиx=2 echo ""
и т.д.)- На время выполнения этой команды
x
устанавливается значение1
- Команда выполняется:
echo ""
Вероятно, вы имели в виду, что эта команда должна состоять из двух инструкций: присвоить значение x
, вывести его значение. Но в синтаксисе оболочки то, что вы написали, было совершенно допустимым кодом, поэтому оболочка выполнила его без возражений.
решение2
Вы просили ответить на два вопроса:
Вы просили объяснить, почему ваш текущий код не выдает ожидаемый результат.
Вы спрашивали, как правильно написать код, чтобы он выдавал ожидаемый результат.
Глядя на ваш код, я вижу два вероятных объяснения того, почему вы написали код именно так:
Может возникнуть небольшая путаница по поводусинтаксис цикла for.
Может возникнуть небольшая путаница относительно порядка оценки в том, что называетсяпростая команда.
синтаксис цикла 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. Обе эти ссылки включают следующий отрывок:
«Простая команда» — это последовательность необязательных назначений переменных и перенаправлений в любой последовательности, за которой могут следовать слова и перенаправления, завершаемая оператором управления.
Когда требуется выполнить заданную простую команду (то есть, когда любая условная конструкция, такая как список И-ИЛИ илислучайоператор не обошел простую команду), то следующие расширения, назначения и перенаправления должны быть выполнены от начала текста команды до конца:
Слова, которые распознаются как переменные назначения или перенаправления в соответствии сПравила грамматики Shellсохраняются для обработки на шагах 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