Завидовать или не завидовать

32

В чем разница между командами

$ env FOO=bar baz

а также

$ FOO=bar baz

Какой эффект envимеет?

Август Карлстрем
источник
4
Что-то вроде побочного вопроса, но как называется эта функция, когда вы устанавливаете переменную окружения для одной подобной подкоманды? Мне всегда было трудно найти информацию об этом, потому что я не знаю, как это называется.
Джон Кромарти
1
@JohnCromartie, вы должны задать это как вопрос.
CJM
1
Для bash это задокументировано здесь: gnu.org/software/bash/manual/…
Гленн Джекман
2
@JohnCromartie Это необязательный компонент каждой команды оболочки, поэтому он находится в разделе «Простые команды» большинства руководств по оболочке. Для POSIX это было бы здесь . Гленн связал аналогичный раздел из руководства по bash для вас.
jw013
Установка переменной, которая не существует с помощью присваивания, создает переменную оболочки. Установка его через ENV или экспорт переменной помещает переменную в среду выполнения оболочки. Изменение значения существующей переменной обновит значение среды выполнения, если оно существует, в противном случае измените его во внутренних переменных оболочки.
Йохан

Ответы:

26

Они функционально эквивалентны.

Основное различие заключается в том, что вы env FOO=bar bazвызываете промежуточный процесс между оболочкой и baz, как и в случае с FOO=bar bazоболочкой, напрямую baz.
Так что в этом отношении FOO=bar bazпредпочтительнее.

Единственные ситуации, в которых я нахожусь, env FOO=bar- это когда я должен передать команду другой команде.
В качестве конкретного примера, допустим, у меня есть скрипт-обертка, который выполняет некоторые модификации среды, а затем вызывает execпереданную ему команду, такую ​​как:

#!/bin/bash
FOO=bob
some stuff
exec "$@"

Если вы выполните его как myscript FOO=bar baz, он execвыдаст ошибку как exec FOO=bar bazнедействительную.
Вместо этого вы называете его так, как оно myscript env FOO=bar bazвыполняется exec env FOO=bar baz, и является совершенно допустимым.

Патрик
источник
1
Вы можете сделать, FOO=bar exec bazхотя, так что вам не нужно envв последнем пункте.
Стефан Шазелас
Когда вы execчто-то используете, это использует ваше текущее окружение?
Гленн Джекман
1
Так же @StephaneChazelas, и вы также sudo FOO=bar bazможете передавать переменные окружения без необходимости env.
Майк Миллер
1
@StephaneChazelas, который работает, только если я хочу вставить FOO=barв сценарий. Если FOOне всегда bar, я не хочу жестко его кодировать, а вместо этого передать.
Патрик
@glennjackman да, да, если переменные экспортируются или передаются до exec, например FOO=bar exec baz.
Патрик
14

В этом конкретном примере нет эффективной разницы, если предположить, что ваша оболочка является POSIX-совместимой оболочкой, и предполагается, bazчто это исполняемый файл, а не встроенная оболочка.

Если ваша оболочка не является POSIX-совместимой оболочкой, например, cshили tcsh, синтаксис

FOO=bar baz

не работает, и нет эквивалентного синтаксиса оболочки. Для этих оболочек envкоманда является единственным способом переопределить или внедрить переменные среды для одной команды.

Если bazэто встроенная оболочка, скажем, fcнапример, то envона не даст таких же результатов, потому что envвыполняет новый процесс вместо того, чтобы запускаться непосредственно командной оболочкой. Более того, fcисполняемого файла нет , его можно запускать только как встроенную оболочку из-за того, как он взаимодействует со средой оболочки и поэтому никогда неenv будет работать со встроенным подобным .fc

Кроме того, envпредлагается -iопция, позволяющая запустить команду в пустой среде только с указанным набором переменных среды. Так что envможет быть очень полезным для запуска процессов в санитарных средах, например

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz
Майк Миллер
источник
Когда я использовал, tcshя писал, (setenv FOO bar; baz)чтобы получить эквивалентную функцию.
Бармар
6

В дополнение к тому, что уже было сказано

VAR=value cmd args > redirs

Будучи функцией оболочки (Bourne / POSIX), вы ограничены в именах переменных среды, которые вы передаете cmd. Они должны быть допустимыми именами переменных оболочки и не должны быть только для чтения или специальными переменными для оболочки.

Например, вы не можете сделать:

1=foo cmd

Или

+++=bar cmd

bash не позволяет вам делать:

SHELLOPTS=xtrace cmd

Пока вы можете сделать:

env 1=foo cmd
env +++=bar cmd
env '=baz' cmd

(не то, что вы хотите или должны хотеть сделать это). Или:

env SHELLOPTS=xtrace cmd

(Мне иногда нужно это делать).

Обратите внимание, что envвы по-прежнему не можете передать строку переменной среды, которая не содержит =(не то, что вы хотели бы сделать это либо).

Стефан Шазелас
источник
2

Одним из применений envявляется возможность $PATHпоиска исполняемых файлов в строках shebang (потому что envучитывает $PATHпри поиске исполняемого файла). Это полезно, если исполняемый файл, который вы хотите вызвать, может находиться в разных местах на разных машинах. Например,

#!/usr/bin/env perl

в первой строке скрипта с установленным исполняемым битом этот скрипт будет выполняться с Perl, независимо от того, установлен он в /usr/bin/perlили в /usr/local/bin/perlдругом месте или в совершенно другом месте, если каталог находится в пути.

Конечно, поиск по пути сопряжен с дополнительным риском, но тогда риск не больше, чем если бы вы написали явно perl yourscript.pl, что также ищет perl в пути поиска.

celtschk
источник
2

В другой раз, когда envэто действительно полезно, вы хотите полностью контролировать окружающую среду. Я запускаю серверную программу (Informix, если вы не можете догадаться), окружение которой я хочу полностью контролировать. Я запускаю его, используя envв конце скрипта, который устанавливает кучу переменных на правильные значения:

env -i HOME="$IXD" \
       INFORMIXDIR="$IXD" \
       INFORMIXSERVER="$IXS" \
       ${IXC:+INFORMIXCONCSMCFG="$IXC"} \
       ${IXH:+INFORMIXSQLHOSTS="$IXH"} \
       IFX_LISTEN_TIMEOUT=3 \
       ONCONFIG="onconfig.$IXS" \
       PATH="/bin:/usr/bin:$IXD/bin" \
       SHELL=/bin/ksh \
       TZ=UTC0 \
    $ONINIT "$@"

-iВариант существующей хочет подарить Петербург окружающей среды. Последующие VAR=valueпараметры устанавливают переменные среды, которые я хочу установить; имя программы находится в $ONINIT, и любые аргументы командной строки передаются через дословно с "$@".

${IXH:+INFORMIXSQLHOSTS="$IXH"}Конструкция проходит только INFORMIXSQLHOSTS="$IXH"в envслучае $IXHустанавливается в непустое значение.

Джонатан Леффлер
источник