Сбросить переменную среды для одной команды

24

Я могу бежать, ENV_VAR=value commandчтобы бежать commandс определенным значением для ENV_VAR. Что эквивалентно unset ENV_VARдля command?

Алексей романов
источник
7
В сторону: commandнеудачный выбор заполнителей, поскольку на самом деле есть встроенная команда с таким именем. mycommandили что- somecommandто подобное может стать лучшей привычкой.
Чарльз Даффи
@CharlesDuffy, я обычно использую cmdдля этого.
Стефан

Ответы:

35

За исключением -iопции, которая стирает всю среду, POSIX envне предоставляет никакого способа сброса переменной.

Однако, с несколькими envреализациями (включая GNU, busybox'и, по крайней мере, FreeBSD), вы можете сделать:

env -u ENV_VAR command

Что будет работать при удалении каждого экземпляра ENV_VARпеременной из среды (обратите внимание, что она не работает для переменной среды с пустым именем ( env -u ''либо выдает ошибку, либо неэффективна в зависимости от реализации, даже если все принимают env '=value', возможно, ограничение понесенные unsetenv()функции C , которая POSIX требует , чтобы вернуть ошибку для пустой строки, в то время как нет такого ограничения для putenv())).

Портативно (в оболочках POSIX) вы можете сделать:

(unset -v ENV_VAR; exec command)

(обратите внимание, что с некоторыми оболочками, использование execможет изменить то, что commandзапускается: запускает тот, что в файловой системе вместо функции или встроенной функции (например, и обойдется без aliasрасширения, очевидно), как envописано выше. Вы бы хотели опустить его в этих случаях) ,

Но это не сработает для переменных среды, имена которых не сопоставимы с переменной оболочки (обратите внимание, что некоторые оболочки, как, в mkshлюбом случае, удаляют эти переменные из среды при запуске) или переменные, помеченные как доступные только для чтения.

-vпредназначен для оболочки Bourne и без bashкоторого может сбросить функцию, если переменная с таким именем не существует. Большинство других оболочек не отменят функции, если вы не передадите опцию. (вряд ли что-то изменит на практике).unset-vENV_VAR -f

(Также остерегайтесь об ошибке / ошибочной особенности из bash/ mksh/ yashкоторого unset, при некоторых обстоятельства не могут сбросить переменные, но показывают переменный во внешней области видимости )

Если perlдоступно, вы можете сделать:

perl -e 'delete $ENV{shift@ARGV}; exec @ARGV or die$!' ENV_VAR command

Который будет работать даже для переменной среды с пустым именем.

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

env -u LANG printf -v var %.3f 1.2 # would run /usr/bin/printf instead
(unset -v LANG; printf -v var %.3f 1.2) # changes to $var lost afterwards

(здесь отключение LANG как ошибочного подхода при проверке .используется и понимается как десятичный разделитель. Было бы лучше использовать LC_ALL=C printf...для этого)

С некоторыми оболочками вы можете вместо этого создать локальную область видимости для переменной, используя функцию:

without() {
  local "$1" # $1 variable declared as initially unset in bash¹
  shift
  "$@"
}
without LANG printf -v var %.3f 1.2

С помощью zshвы также можете использовать анонимную функцию:

(){local ENV_VAR; command}

Этот подход не будет работать в некоторых оболочках (например, основанных на оболочке Almquist), которые localне объявляют переменную как изначально не установленную (но наследуют значение и атрибуты). В тех, которые вы можете сделать local ENV_VAR; unset ENV_VAR, но не делайте этого в mkshили yash( typesetвместо localэтого), так как это не сработает, unsetбудет только отмена local.

Be Также имейте в bashвиду, что локальный ENV_VAR(хотя и не установленный) сохранит атрибут экспорта . Таким образом, если бы это commandбыла функция, которая присваивает значение ENV_VAR, переменная была бы доступна в среде команд, вызываемых впоследствии. unset ENV_VARочистит этот атрибут. Или вы можете использовать local +x ENV_VARметод, который также обеспечит чистую доску (если эта переменная не была объявлена ​​только для чтения, но тогда вы ничего не можете с этим поделать bash).

Стефан Шазелас
источник
1
Это отдельный вопрос, но что, черт возьми, это переменная среды с пустым именем и как бы вы ее использовали - даже для какого-то подвига? Разве вы не должны написать программу, которая читает среду и специально ищет что-то подобное?
Джо
@ Джо, попробуй например env '=foo' python -c 'import os; print os.environ[""]'. Я не ожидаю, что многие люди захотят установить такую ​​переменную.
Стефан
9

Насколько я знаю, прямого эквивалента нет; Вы можете использовать подоболочку:

(unset ENV_VAR; exec command)
Стивен Китт
источник
(unset ENV_VAR; exec somecommand)если вы хотите быть эквивалентны оригиналу по эффективности (потребляя подоболочку). Как это, это добавляет дополнительную вилку.
Чарльз Даффи
1
@Charles, хотя некоторые оболочки делают это автоматически, так commandкак это последняя команда в вызове подоболочки.
Стивен Китт
+1, потому что этот способ прост для ввода в интерактивном режиме. Я использую подоболочки для одноразовых изменений в оболочке для однострочного текста вместо того, чтобы помнить, что это так env -u.
Питер Кордес
0

Вы можете использовать ENV_VAR= command

Это на самом деле не сбрасывает переменную, но может быть полезно во многих случаях (сценарии оболочки обычно просто используют test -nдля проверки, установлена ​​ли переменная):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
ВНП
источник