В чем разница между set, export и env и когда мне следует использовать каждый из них?

112

Время от времени я собираю сценарий bash, и мне кажется, что есть несколько способов установки переменной:

key=value
env key=value
export key=value

Когда вы находитесь внутри скрипта или отдельной команды (например, я часто связываю переменную с помощью средства запуска Wine для установки правильного префикса Wine), они кажутся полностью взаимозаменяемыми, но, конечно, это не может иметь место.

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

Определенно связано с тем, В чем разница между `VAR = ...` и `export VAR = ...`? но я хочу знать, как envвписывается в это тоже, и некоторые примеры, показывающие преимущества каждого из них тоже было бы неплохо :)

Оли
источник
5
Обратите внимание, что export key=valueэто расширенный синтаксис и не должен использоваться в переносимых сценариях (то есть #! /bin/sh).
Саймон Рихтер

Ответы:

110

Давайте рассмотрим конкретный пример. Команда grepиспользует переменную среды, вызываемую GREP_OPTIONSдля установки параметров по умолчанию.

В настоящее время. Учитывая, что файл test.txtсодержит следующие строки:

line one
line two

выполнение команды grep one test.txtвернет

line one

Если вы запустите grep с -vпараметром, он вернет несовпадающие строки, поэтому вывод будет

line two

Теперь мы попытаемся установить параметр с переменной среды.

  1. Переменные среды, установленные без export, не будут наследоваться в среде команд, которые вы вызываете.

    GREP_OPTIONS='-v'
    grep one test.txt

    Результат:

    line one

    Очевидно, что вариант -vне был передан grep.

    Вы хотите использовать эту форму, когда вы устанавливаете переменную только для оболочки, например, for i in * ; doесли вы не хотите экспортировать $i.

  2. Тем не менее, переменная передается в среду этой конкретной командной строки, так что вы можете сделать

    GREP_OPTIONS='-v' grep one test.txt

    который вернет ожидаемое

    line two

    Вы используете эту форму для временного изменения среды данного конкретного экземпляра запущенной программы.

  3. Экспорт переменной приводит к наследованию переменной:

    export GREP_OPTIONS='-v'
    grep one test.txt

    возвращается сейчас

    line two

    Это наиболее распространенный способ установки переменных для использования впоследствии запущенных процессов в оболочке.

  4. Все это было сделано в Bash. exportэто встроенный bash; VAR=whateverэто синтаксис bash envс другой стороны, это программа сама по себе. Когда envвызывается, происходят следующие вещи:

    1. Команда envвыполняется как новый процесс
    2. env модифицирует окружающую среду и
    3. вызывает команду, указанную в качестве аргумента. envПроцесс заменяется commandпроцессом.

    Пример:

    env GREP_OPTIONS='-v' grep one test.txt

    Эта команда запустит два новых процесса: (i) env и (ii) grep (фактически, второй процесс заменит первый). С точки зрения grepпроцесса, результат в точности совпадает с

    GREP_OPTIONS='-v' grep one test.txt

    Однако вы можете использовать эту идиому, если вы находитесь за пределами bash или не хотите запускать другую оболочку (например, когда вы используете exec()семейство функций, а не system()вызов).

Дополнительная заметка о #!/usr/bin/env

Это также, почему идиома #!/usr/bin/env interpreterиспользуется, а не #!/usr/bin/interpreter. envне требует полного пути к программе, потому что она использует execvp()функцию, которая ищет PATHпеременную, как это делает оболочка, а затем заменяет себя командой run. Таким образом, его можно использовать, чтобы узнать, где интерпретатор (например, perl или python) «сидит» на пути.

Это также означает, что, изменяя текущий путь, вы можете влиять на то, какой вариант Python будет вызываться. Это делает возможным следующее:

echo -e '#!/usr/bin/bash\n\necho I am an evil interpreter!' > python
chmod a+x ./python
export PATH=.
calibre

вместо запуска Caliber, приведет к

I am an evil interpreter!
январь
источник
Почему GREP_OPTIONS = '- v' grep one test.txt работает? Я думал, что после '-v' нужна точка с запятой (но я попробовал, и это действительно работает.)
Джо
2
Потому что с точкой с запятой это интерпретируется как две отдельные команды bash; первый устанавливает переменную (без ее экспорта), а второй начинается со среды, в которой переменная не экспортируется. Однако без точки с запятой это одна команда (grep), которой предшествует настройка локальной среды.
январь
Откуда берутся все переменные env? Я имею в виду, когда вы открываете новую оболочку, у вас всегда есть несколько переменных. Так что какая-то программа должна была их exportредактировать, верно?
Питикос
1
@Pithikos Переменные среды устанавливаются "источником среды". По умолчанию bash будет использовать общесистемный bashrc (или profile.d или bash_profile). Затем он получает ваш пользователь ~ / .bashrc (и / или ~ / .bash_profile). Любой из этих файлов может содержать команды bash для создания других сценариев, поэтому в конечном итоге вы можете получать переменные окружения повсюду.
Эрик
5
Как насчет set var=blah?
CMCDragonkai