Неожиданное поведение в Баш

7

От man bash:

A simple command is a sequence of optional variable assignments
followed by blank-separated words and redirections, and
terminated by a control operator. The first word specifies the
command to be executed, and is passed as argument zero. The
remaining words are passed as arguments to the invoked command.

Так что совершенно законно написать:

foo=bar echo $foo

но он не работает, как я ожидаю (он печатает только новую строку). Это довольно странно для меня, так как:

$ foo=bar printenv
foo=bar
TERM=rxvt-unicode
[...]

Может кто-нибудь объяснить мне, где я делаю неправильно?

cYrus
источник

Ответы:

6

Это происходит потому, что расширение переменной выполняется до запуска команды. В то время, когда происходит расширение переменной, foo не установлен, поэтому он расширяется до пустой строки. Затем команда запускается, установив foo,

Daenyth
источник
1
Также обратите внимание, что, поскольку foo установлен в качестве префикса для команды echo, он устанавливается только для этой команды (а не для последующих команд). Сравнить с foo=bar eval 'echo eval sees $foo'; echo echo sees $foo (здесь, так как $foo расширяется в пределах eval команда, значение будут быть заменен там, но не для следующей команды эха).
Gordon Davisson
1
Это задание в среде ребенка (т.е. echo в оригинальном вопросе или eval в примере Гордона). Переменные в дочерней среде не влияют на значения переменных в родительской среде. foo=bar eval 'foo=$foo'; echo $foo выводит только перевод строки.
Dennis Williamson
От man bash: "Если имя команды не появляется, назначения переменных влияют на текущую среду оболочки. В противном случае переменные добавляются в среду выполняемой команды и не влияют на текущую среду оболочки. Если какое-либо из назначений пытается присвоить значение переменная только для чтения, возникает ошибка, и команда завершается с ненулевым статусом. "
Dennis Williamson
1

Если вы делаете foo=bar а также echo $foo на одной линии это не сработает. Вам придется сделать одну из трех вещей.

  1. Запустите их как отдельные команды. то есть: foo=bar Войти echo $foo

  2. Запустите их в одну строку, но с запятой между ними. то есть: foo=bar; echo $foo

  3. То же, что № 2, но с двойными амперсандами. то есть: foo=bar && echo $foo

Разница между 2 и 3 в том, что 3 будет выполнять только echo $foo если foo=bar удалось.

Wuffers
источник
Спасибо, но я знаю, как обойти эту проблему. Меня интересовал только пример, который я привел.
cYrus
+1: Хотя хороший набор альтернатив. Это может пригодиться кому-то.
cYrus
0

Пытаться:

foo=bar; echo $foo
       ^

Следите за ; так как вы пытаетесь разместить две отдельные команды в одной строке. По умолчанию они не работают вместе.

BloodPhilia
источник
0

Правильный способ сделать это будет:

foo=bar sh -c 'echo $foo'
jlliagre
источник