Como manter variáveis ​​de ambiente ao usar o sudo

425

Quando eu uso qualquer comando com sudo, as variáveis ​​de ambiente não estão lá. Por exemplo, depois de definir HTTP_PROXY, o comando wgetfunciona bem sem sudo. No entanto, se eu digitar, sudo wgetele diz que não pode ignorar a configuração de proxy.

Ahmed Aswani
fonte

Respostas:

475

Primeiro você precisa export HTTP_PROXY. Segundo, você precisa ler man sudoatentamente e prestar atenção à -Ebandeira. Isso funciona:

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

Aqui está a citação da página de manual:

-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.
Russo empregado
fonte
1
grande o único problema que é modificar alguns arquivos de configuração, por exemplo pacman para o arco para fazer a -E é passado
Ahmed Aswani
7
Para permitir -E (preservar ambiente) para o wget, é necessário especificar a tag SETENV na regra sudo que permite a execução do wget - Exemplo: <nome do usuário> ALL = (root) NOPASSWD: SETENV: <caminho para o wget>
João Bowers
66
Este "-E" não funciona se a variável for PATH ou PYTHONPATH.
apporc 27/06/16
Também não funciona com nenhuma LC_*variável. Então, basta fazer export LOL_FOO=$LC_FOOe usar LOL_FOO.
luckydonald
9
Isto não funcionou com o caso mais simples de adicionar um elemento para o PATHno .bashrcarquivo - digamos, export PATH=myPath:$PATH. Se eu digitar sudo -E bash -c 'echo $PATH', PATHprovavelmente não conterá myPath porque provavelmente sudojá desabilitou o valor local de PATHantes de chamar bash. Em vez disso, eu encontrei a resposta abaixo stackoverflow.com/a/33183620/5459638 eficaz, isto ésudo PATH=$PATH command
XavierStuvw
310

O truque é adicionar variáveis ​​de ambiente ao sudoersarquivo via sudo visudocomando e adicionar estas linhas:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

extraído do wiki do ArchLinux .

Para o Ubuntu 14, você precisa especificar em linhas separadas, pois ele retorna os erros para linhas com várias variáveis:

Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"
Ahmed Aswani
fonte
11
Esta é sem dúvida a melhor opção, para evitar vazamento de informações e falhas de segurança. sudo -Eé a maneira infalível de adhoc obter o mesmo efeito em uma única
ocorrência
Eu encontrei o problema de um processo ser aquele que chama sudo (jhbuild) e não posso dizer para ele passar o sinalizador -E para sudo, então essa é a minha solução.
Jgomo3 13/05
61
Observe que você nunca deve editar o etc/sudoersdiretamente. Em vez disso, use o visudocomando, que verifica a sintaxe de suas edições antes de substituir o sudoersarquivo. Dessa forma, você não se trava se cometer um erro durante a edição.
Henning
1
Considere usar envs em maiúsculas. No meu caso, o uso de HTTP_PROXY e HTTPS_PROXY fez o truque.
pabo
2
variante minúscula é melhor da minha experiência, pois funciona tanto no wget quanto no curl.
Miroslav Mocek
57

Para variáveis ​​individuais que você deseja disponibilizar de uma só vez, você pode torná-lo parte do comando.

sudo http_proxy=$http_proxy wget "http://stackoverflow.com"
buckaroo1177125
fonte
Eu testei essa resposta para uma packagesob algum myPath adicionado a PATHno .bashrcarquivo (com exportclausule). Então sudo PATH=$PATH which packageencontra a resposta certa, ao contrário sudo which package. No entanto, sudo PATH=$PATH packagenão vai além de sudo package(arquivo não encontrado). Por outro lado, lançar uma planície a packagepartir de uma concha invocada com sudo bashpreserva o caminho estendido e concede packagedireitos ao sudo (dois pombos com uma pedra). Portanto, a resposta realmente depende de quais comandos você está iniciando
#
2
Resolução PATH para sudo é outra questão - se alguém encontrar este post em busca de que o assunto sugiro ver unix.stackexchange.com/questions/83191/...
buckaroo1177125
24

Você também pode combinar as duas env_keepdeclarações da resposta de Ahmed Aswani em uma única declaração como esta:

Defaults env_keep += "http_proxy https_proxy"

Você também deve especificar env_keepapenas um comando como este:

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

Stian S
fonte
1

Uma função simples de wrapper (ou em linha para loop)

Eu vim com uma solução única porque:

  • sudo -E "$@" estava vazando variáveis ​​que estavam causando problemas para o meu comando
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" foi longo e feio no meu caso

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

Resultado

$ ./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.

Quão?

Isso é possível graças a um recurso do bash embutido printf. O %qproduz uma seqüência de caracteres citada pelo shell. Ao contrário da expansão de parâmetro no bash 4.4 , isso funciona nas versões do bash <4.0

Bruno Bronosky
fonte
0

Se você precisar manter as variáveis ​​de ambiente em um script, poderá colocar seu comando em um documento aqui como este. Especialmente se você tiver muitas variáveis ​​para definir as coisas, dessa forma, arrume-as.

# 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
Wolfgang Fahl
fonte