使用sudo时如何保持环境变量

Ahm*_*ani 395 linux sudo environment-variables

当我使用sudo的任何命令时,环境变量不存在.例如,在设置HTTP_PROXY之后,该命令wget可以正常工作sudo.但是,如果我键入sudo wget它说它无法绕过代理设置.

Emp*_*ian 449

首先你需要export HTTP_PROXY.其次,你需要man sudo仔细阅读,并注意-E旗帜.这有效:

$ export HTTP_PROXY=foof
$ sudo -E bash -c 'echo $HTTP_PROXY'
Run Code Online (Sandbox Code Playgroud)

以下是手册页中的引用:

-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.
Run Code Online (Sandbox Code Playgroud)

  • 如果变量是PATH或PYTHONPATH,则此"-E"不起作用. (56认同)
  • 这不适用于在`.bashrc`文件中向`PATH`添加一个元素的简单情况 - 例如,`export PATH = myPath:$ PATH`.如果我键入`sudo -E bash -c'echo $ PATH',那么`PATH`可能不包含myPath,因为`sudo`在调用`bash`之前已经禁用了`PATH`的本地值.相反,我发现http://stackoverflow.com/a/33183620/5459638下面的答案有效,那就是`sudo PATH = $ PATH命令 (8认同)
  • 要为wget允许-E(保留环境),您需要在允许运行wget的sudo规则上指定SETENV标记 - 示例:<username> ALL =(root)NOPASSWD:SETENV:<wget的路径> (6认同)

Ahm*_*ani 293

诀窍是sudoers通过sudo visudo命令将环境变量添加到文件并添加以下行:

Defaults env_keep += "ftp_proxy http_proxy https_proxy no_proxy"
Run Code Online (Sandbox Code Playgroud)

取自ArchLinux wiki.

对于Ubuntu 14,您需要在单独的行中指定,因为它返回多变量行的错误:

Defaults  env_keep += "http_proxy"
Defaults  env_keep += "https_proxy"
Defaults  env_keep += "HTTP_PROXY"
Defaults  env_keep += "HTTPS_PROXY"
Run Code Online (Sandbox Code Playgroud)

  • 请注意,您应该*永远不要*直接编辑`etc/sudoers`.相反,使用`visudo`命令,在覆盖`sudoers`文件之前对语法进行语法检查.这样,如果您在编辑时出错,则不会将自己锁定. (57认同)
  • 这可以说是避免信息泄漏和安全漏洞的最佳选择.但是,sudo -E`是adhoc获得相同效果的必然结果 (11认同)
  • 从我的经验来看,小写变体更好,因为它在wget和curl中都有效. (2认同)

buc*_*125 55

对于您想要一次性使用的单个变量,您可以将其作为命令的一部分.

sudo http_proxy=$http_proxy wget "http://stackoverflow.com"
Run Code Online (Sandbox Code Playgroud)

  • sudo的PATH解析是另一回事-如果有人找到该帖子以寻找该问题,我建议您参阅http://unix.stackexchange.com/questions/83191/how-to-make-sudo-preserve-path (2认同)

小智 23

您也可以将env_keepAhmed Aswani答案中的两个陈述合并为一个这样的语句:

Defaults env_keep += "http_proxy https_proxy"

您还应该考虑env_keep仅指定一个这样的命令:

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


Bru*_*sky 5

一个简单的包装函数(或内联 for 循环)

我想出了一个独特的解决方案,因为:

  • sudo -E "$@" 正在泄漏导致我的命令出现问题的变量
  • sudo VAR1="$VAR1" ... VAR42="$VAR42" "$@" 在我的情况下又长又丑

演示文件

#!/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
Run Code Online (Sandbox Code Playgroud)

结果

$ ./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.
Run Code Online (Sandbox Code Playgroud)

如何?

这是通过 bash 内置功能实现的printf。将%q产生一个shell引号的字符串。与bash 4.4 中的参数扩展不同,这适用于 bash 版本 < 4.0