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

Каждый раз так, что я выхожу из сценария bash, и мне кажется, что есть несколько способов установки переменной:

key=value env key=value export key=value 

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

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

Определенно связано с тем, в чем разница между «VAR = …» и «export VAR = …»? но я хочу знать, как env вписывается в это тоже, и некоторые примеры, показывающие преимущества каждого, были бы хороши тоже 🙂

Рассмотрим конкретный пример. Команда 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 .

    Вы хотите использовать эту форму, когда вы устанавливаете переменную только для используемой оболочки, например in 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 builtin; 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 же, как это делает оболочка, а затем заменяет собой запуск команды. Таким образом, его можно использовать, чтобы выяснить, где интерпретатор (например, perl или python) «сидит» на пути.

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

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

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

 I am an evil interpreter!