Bash: указание переменных среды для echo в командной строке?
рассмотрим этот фрагмент:
$ SOMEVAR=AAA
$ echo zzz $SOMEVAR zzz
zzz AAA zzz
здесь я поставил $SOMEVAR до AAA на первой строке - и когда я эхо его на второй строке, я получаю AAA содержание, как ожидалось.
но тогда, если я попытаюсь указать переменную в той же командной строке, что и echo:
$ SOMEVAR=BBB echo zzz $SOMEVAR zzz
zzz AAA zzz
... Я не получаю BBB как я и ожидал-я получаю старое значение (AAA).
это то, как все должно быть? Если да, то как же тогда вы можете укажите переменные типа LD_PRELOAD=/... program args ... и это работает? Чего мне не хватает?
6 ответов:
то, что вы видите-это ожидаемое поведение. Беда в том, что родительская оболочка оценивает
$SOMEVARв командной строке перед вызовом команды с измененной среды. Вам нужно получить оценку$SOMEVARотложена до среды.ваши непосредственные варианты включают в себя:
SOMEVAR=BBB eval echo zzz '$SOMEVAR' zzz.SOMEVAR=BBB sh -c 'echo zzz $SOMEVAR zzz'.оба они используют одинарные кавычки, чтобы предотвратить родительскую оболочку от оценки
$SOMEVAR; он вычисляется только после его установки в среде (временно, на время выполнения одной команды).другой вариант-использовать нотацию суб-оболочки (как также предложено Маркус Кун в своем ответ):
(SOMEVAR=BBB; echo zzz $SOMEVAR zzz)переменная устанавливается только в суб-оболочке
Проблема, Вновь
откровенно говоря, руководство сбивает с толку по этому вопросу. Элемент руководство GNU Bash говорит:
среда для любой простой команды или функции [обратите внимание, что это исключает встроенные элементы] может быть временно дополнена префиксом с назначением параметров, как описано в разделе Параметры оболочки. Эти операторы присваивания влияют только на среду, видимую этой командой.
если вы действительно разобрать предложение, что он говорит, что окружающая среда для команды/функции изменяется, но не среда для родительского процесса. Итак, это будет работать:
$ TESTVAR=bbb env | fgrep TESTVAR TESTVAR=bbbпотому что среда для команды env была изменена перед ее выполнением. Однако это не сработает:
$ set -x; TESTVAR=bbb echo aaa $TESTVAR ccc + TESTVAR=bbb + echo aaa ccc aaa cccиз-за того, когда расширение параметра выполняется оболочкой.
Действия Переводчика
другая часть проблемы заключается в том, что Баш определяет эти шаги для своего переводчика:
- считывает входные данные из файла (см. скрипты), из строки предоставляется в качестве аргумента для параметра вызова-c (см. раздел вызов Bash), или с терминала пользователя.
- разбивает ввод на слова и операторы, подчиняясь правилам цитирования описано в цитировании. Эти маркеры разделены метасимволами. Расширение псевдонима выполняется этим шагом (см. псевдонимы).
- анализирует маркеры на простые и составные команды (см. команды).
- выполняет различные расширения оболочки (см. расширения оболочки), нарушая расширенные маркеры в списках имена (см. именем Расширение) и команд и аргументов.
- выполняет все необходимые перенаправления (см. перенаправление) и удаляет операторы перенаправления и их операнды из списка аргументов.
- выполняет команду (см. раздел выполнение команд).
- дополнительно ждет для завершения команды и сбора ее выхода статус (см. статус выхода).
что здесь происходит, так это то, что builtins не получают свою собственную среду выполнения, поэтому они никогда не видят измененную среду. Кроме того, простые команды (например, /bin/echo) сделать получить модифицированную ennvironment (именно поэтому пример env работал), но расширение оболочки происходит в настоящее среда в шаге № 4.
другими словами, вы не передавайте 'aaa $TESTVAR ccc' в /bin/echo; вы передаете интерполированную строку (как развернуто в текущей среде) в /bin/echo. В этом случае, так как текущая среда не имеет TESTVAR, вы просто передаете' aaa ccc ' команде.
резюме
документация может быть намного понятнее. Хорошо, что есть переполнение стека!
посмотреть Также
http://www.gnu.org/software/bash/manual/bashref.html#Command-Execution-Environment
чтобы достичь желаемого, используйте
( SOMEVAR=BBB; echo zzz $SOMEVAR zzz )причина:
вы должны отделить назначение точкой с запятой или новой строкой от следующей команды, иначе она не будет выполнена до расширения параметр произойдет для следующей команды (Эхо).
вы должны сделать назначение внутри subshell среда, чтобы убедиться, что он не сохраняет за текущий линия.
Это решение короче, аккуратнее и эффективнее, чем некоторые из других предложенных, в частности, оно не создает новый процесс.
причина в том, что это устанавливает переменную окружения для одной линии. Но,
echoне делает расширение,bashделает. Следовательно, ваша переменная фактически расширяется до выполнения команды, даже еслиSOME_VAR- этоBBBв контексте команды echo.чтобы увидеть эффект, вы можете сделать что-то вроде:
$ SOME_VAR=BBB bash -c 'echo $SOME_VAR' BBBздесь переменная не раскрывается до тех пор, пока не будет выполнен дочерний процесс, поэтому вы видите обновленное значение. если вы проверите
SOME_VARIABLEснова в родительская оболочка, это все ещеAAA, как ожидалось.
SOMEVAR=BBB; echo zzz $SOMEVAR zzzиспользуйте a ; для разделения операторов, которые находятся в одной строке.
Comments