Cómo mantener variables de entorno cuando se usa sudo

425

Cuando uso cualquier comando con sudo, las variables de entorno no están allí. Por ejemplo, después de configurar HTTP_PROXY, el comando wgetfunciona bien sin él sudo. Sin embargo, si escribo sudo wget, dice que no puede omitir la configuración del proxy.

Ahmed Aswani
fuente
2
superuser.com/questions/232231/...
Ciro Santilli郝海东冠状病六四事件法轮功

Respuestas:

475

Primero debes hacerlo export HTTP_PROXY. En segundo lugar, debe leer man sudoatentamente y prestar atención a la -Ebandera. Esto funciona:

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

Aquí está la cita de la página del 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.
Ruso empleado
fuente
1
genial, el único problema que es modificar algunos archivos de configuración, por ejemplo, pacman for arch para hacer que se pase -E
Ahmed Aswani
77
Para permitir -E (preservar el entorno) para wget, debe especificar la etiqueta SETENV en la regla sudo que permite la ejecución de wget - Ejemplo: <nombre de usuario> ALL = (root) NOPASSWD: SETENV: <ruta de acceso a wget>
John Bowers
66
Este "-E" no funciona si la variable es PATH o PYTHONPATH.
apporc
Tampoco funciona con ninguna LC_*variable. Así que solo hazlo export LOL_FOO=$LC_FOOy úsalo LOL_FOOen su lugar.
luckydonald el
99
Esto no funcionó con el caso más simple de añadir un elemento a PATHen el .bashrcarchivo - por ejemplo, export PATH=myPath:$PATH. Si escribo sudo -E bash -c 'echo $PATH', entonces PATHno contiene myPath probablemente porque sudoya ha deshabilitado el valor local de PATHantes de llamar bash. Más bien, encontré la respuesta a continuación stackoverflow.com/a/33183620/5459638 efectiva, es decirsudo PATH=$PATH command
XavierStuvw
310

El truco consiste en agregar variables de entorno al sudoersarchivo mediante un sudo visudocomando y agregar estas líneas:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"

tomado de ArchLinux wiki .

Para Ubuntu 14, debe especificar en líneas separadas, ya que devuelve los errores para líneas de múltiples variables:

Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"
Ahmed Aswani
fuente
11
Podría decirse que esta es la mejor opción, para evitar fugas de información y agujeros de seguridad. sudo -ESin embargo, esta es la forma segura de ad-hoc obtener el mismo efecto para una única vez
sehe
Encontré el problema de que un proceso es el que llama a sudo (jhbuild) y no puedo decirle que pase la bandera -E a sudo, así que esta es mi solución.
jgomo3
61
Tenga en cuenta que nunca debe editar el etc/sudoersdirectamente. En su lugar, utilice el visudocomando, que sintaxis verifica sus ediciones antes de sobrescribir el sudoersarchivo. De esa manera, no se bloquea si comete un error al editar.
Henning
1
Considere usar mayúsculas y minúsculas. En mi caso, el uso de HTTP_PROXY y HTTPS_PROXY hizo el truco.
pabo
2
La variante en minúscula es mejor desde mi experiencia, ya que funciona tanto en wget como en curl.
Miroslav Mocek
57

Para las variables individuales que desea que estén disponibles de forma única, puede hacer que formen parte del comando.

sudo http_proxy=$http_proxy wget "http://stackoverflow.com"
buckaroo1177125
fuente
He probado esta respuesta para un packagepoco de myPath agregado PATHen el .bashrcarchivo (con exportclausule). Luego sudo PATH=$PATH which packageencuentra la respuesta correcta, a diferencia sudo which package. Sin embargo, sudo PATH=$PATH packageno va más allá de sudo package(archivo no encontrado). Por otro lado, lanzar una llanura packagedesde un caparazón invocado con sudo bashpreserva el camino extendido y otorga packagederechos de sudo (dos palomas de un tiro). Por lo tanto, la respuesta realmente depende de qué comandos está
ejecutando
2
La resolución de la RUTA para sudo es otro asunto: si alguien encuentra esta publicación en busca de ese asunto, sugiero ver unix.stackexchange.com/questions/83191/…
buckaroo1177125
24

También puede combinar las dos env_keepdeclaraciones en la respuesta de Ahmed Aswani en una sola declaración como esta:

Defaults env_keep += "http_proxy https_proxy"

También debe considerar especificar env_keepsolo un comando como este:

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

Stian S
fuente
1

Una función de envoltura simple (o en línea para bucle)

Se me ocurrió una solución única porque:

  • sudo -E "$@" estaba filtrando variables que estaban causando problemas para mi comando
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" fue largo y feo en mi 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.

¿Cómo?

Esto es posible gracias a una característica del bash incorporado printf. El %qproduce una cadena entre comillas. A diferencia de la expansión de parámetros en bash 4.4 , esto funciona en versiones de bash <4.0

Bruno Bronosky
fuente
0

Si tiene la necesidad de mantener las variables de entorno en un script, puede colocar su comando en un documento aquí como este. Especialmente si tiene muchas variables para configurar las cosas, se ven ordenadas de esta manera.

# 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
fuente