Как сохранить переменные окружения при использовании sudo

425

Когда я использую любую команду с sudo, переменных среды там нет. Например, после установки HTTP_PROXY команда wgetработает нормально без sudo. Однако, если я набираю, sudo wgetон говорит, что не может обойти настройку прокси.

Ахмед Асуани
источник
2
superuser.com/questions/232231/…
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功

Ответы:

475

Сначала тебе нужно export HTTP_PROXY. Во-вторых, вы должны man sudoвнимательно прочитать и обратить внимание на -Eфлаг. Это работает:

$ export HTTP_PROXY=foof
$ sudo -E bash -c 'echo $HTTP_PROXY'

Вот цитата из справочной страницы:

-E, --preserve-env
             Indicates to the security policy that the user wishes to preserve their
             existing environment variables.  The security policy may return an error
             if the user does not have permission to preserve the environment.
Занятый русский
источник
1
Великолепно, единственная проблема, которая заключается в изменении некоторых конфигурационных файлов, например, pacman для arch, чтобы пропустить -E
Ахмед Асуани,
7
Чтобы разрешить -E (сохранить среду) для wget, вам нужно указать тег SETENV в правиле sudo, которое разрешает запуск wget - Пример: <username> ALL = (root) NOPASSWD: SETENV: <путь к wget>
Джон Бауэрс
66
Это «-E» не работает, если переменная PATH или PYTHONPATH.
Apporc
Также не работает с любой LC_*переменной. Так что просто делайте export LOL_FOO=$LC_FOOи используйте LOL_FOOвместо этого.
luckydonald
9
Это не работает с более простым случаем добавления одного элемента к PATHв .bashrcфайле - скажем, export PATH=myPath:$PATH. Если я наберу sudo -E bash -c 'echo $PATH', то PATHне содержит myPath, вероятно, потому sudoчто уже отключил локальное значение PATHперед вызовом bash. Скорее, я нашел ответ ниже stackoverflow.com/a/33183620/5459638 эффективным, то естьsudo PATH=$PATH command
XavierStuvw
310

Хитрость заключается в том, чтобы добавить переменные среды в sudoersфайл с помощью sudo visudoкоманды и добавить следующие строки:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

взято из ArchLinux вики .

Для Ubuntu 14 вам нужно указывать в отдельных строках, так как он возвращает ошибки для строк с несколькими переменными:

Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"
Ahmed Aswani
источник
11
Это, пожалуй, лучший вариант, чтобы избежать утечки информации и дыр в безопасности. sudo -Eэто верный способ добиться того же эффекта для одноразового, хотя
sehe
Я столкнулся с проблемой процесса, являющегося тем, кто вызывает sudo (jhbuild), и я не могу сказать ему передать флаг -E в sudo, так что это мое решение.
jgomo3
61
Обратите внимание, что вы никогда не должны редактировать etc/sudoersнапрямую. Вместо этого используйте visudoкоманду, которая синтаксически проверяет ваши изменения перед перезаписью sudoersфайла. Таким образом, вы не заблокируете себя, если допустите ошибку при редактировании.
Хеннинг
1
Рассмотрите возможность использования заглавных букв env. В моем случае использование HTTP_PROXY и HTTPS_PROXY помогло.
Пабо
2
вариант из нижнего регистра лучше моего опыта, так как он работает как в wget, так и в curl.
Мирослав Мочек
57

Для отдельных переменных, которые вы хотите сделать доступными по отдельности, вы можете сделать это частью команды.

sudo http_proxy=$http_proxy wget "http://stackoverflow.com"
buckaroo1177125
источник
Я проверил этот ответ на предмет packageпод myPath, добавленным PATHв .bashrcфайл (с exportклаузулой). Затем sudo PATH=$PATH which packageнаходит правильный ответ, в отличие от sudo which package. Тем sudo PATH=$PATH packageне менее, не идет дальше, чем sudo package(файл не найден). С другой стороны, запуск равнины packageиз оболочки, вызванной с помощью, sudo bashсохраняет расширенный путь и дает packageправа sudo (два голубя с одним камнем). Таким образом, ответ действительно зависит от того, какие команды вы запускаете
XavierStuvw
2
Разрешение PATH для Судо другое дело - если кто - нибудь найти этот пост в поисках этого вопроса я предлагаю увидеть unix.stackexchange.com/questions/83191/...
buckaroo1177125
24

Вы также можете объединить два env_keepутверждения в ответе Ахмеда Асуани в одно утверждение, подобное этому:

Defaults env_keep += "http_proxy https_proxy"

Вам также следует рассмотреть возможность указания env_keepтолько для одной команды, подобной этой:

Defaults!/bin/[your_command] env_keep += "http_proxy https_proxy"

Stian S
источник
1

Простая функция-обертка (или встроенная в цикл)

Я придумал уникальное решение, потому что:

  • sudo -E "$@" текла переменные, которые вызывали проблемы для моей команды
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" было долго и некрасиво в моем случае

demo.sh

#!/bin/bash

function sudo_exports(){
    eval sudo $(for x in $_EXPORTS; do printf '%q=%q ' "$x" "${!x}"; done;) "$@"
}

# create a test script to call as sudo
echo 'echo Forty-Two is $VAR42' > sudo_test.sh
chmod +x sudo_test.sh

export VAR42="The Answer to the Ultimate Question of Life, The Universe, and Everything."

export _EXPORTS="_EXPORTS VAR1 VAR2 VAR3 VAR4 VAR5 VAR6 VAR7 VAR8 VAR9 VAR10 VAR11 VAR12 VAR13 VAR14 VAR15 VAR16 VAR17 VAR18 VAR19 VAR20 VAR21 VAR22 VAR23 VAR24 VAR25 VAR26 VAR27 VAR28 VAR29 VAR30 VAR31 VAR32 VAR33 VAR34 VAR35 VAR36 VAR37 VAR38 VAR39 VAR40 VAR41 VAR42"

# clean function style
sudo_exports ./sudo_test.sh

# or just use the content of the function
eval sudo $(for x in $_EXPORTS; do printf '%q=%q ' "$x" "${!x}"; done;) ./sudo_test.sh

Результат

$ ./demo.sh
Forty-Two is The Answer to the Ultimate Question of Life, The Universe, and Everything.
Forty-Two is The Answer to the Ultimate Question of Life, The Universe, and Everything.

Как?

Это стало возможным благодаря функции встроенного в bash printf. %qПроизводит оболочки кавычек. В отличие от расширения параметров в bash 4.4 , это работает в версиях bash <4.0

Бруно Броноски
источник
0

Если вам нужно сохранить переменные окружения в скрипте, вы можете поместить свою команду в документ здесь, например так. Особенно, если у вас много переменных, чтобы все выглядело аккуратно.

# prepare a script e.g. for running maven
runmaven=/tmp/runmaven$$
# create the script with a here document 
cat << EOF > $runmaven
#!/bin/bash
# run the maven clean with environment variables set
export ANT_HOME=/usr/share/ant
export MAKEFLAGS=-j4
mvn clean install
EOF
# make the script executable
chmod +x $runmaven
# run it
sudo $runmaven
# remove it or comment out to keep
rm $runmaven
Вольфганг Фаль
источник