brief introduction
Under the normal user, setting and export ing a variable, then executing echo command with sudo, can get the value of the variable. But if the echo command is written into the script, then sudo executes the script, the variable can not be found, and the value can not be obtained. The following is the case:
$ cat tesh.sh
echo $var
$ var=aaa
$ export var # export variable
$ sudo echo $var # sudo executes echo commands, returning variable values
aaa
$ sudo bash test.sh # sudo executes scripts and cannot get variable values
$ bash test.sh # Ordinary users execute scripts and return variable values
aaa
Reason
When sudo runs, it defaults to reset the environment variable to a safe environment variable, that is, the previously set variables will fail, and only a few of the environment variables specified in the configuration file can be saved.
The sudo configuration file is / etc/sudoers that requires root privileges to read:
$ sudo sed '/^#/d;/^$/d' /etc/sudoers
Defaults env_reset
Defaults mail_badpass
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
root ALL=(ALL:ALL) ALL
%sudo ALL=(ALL:ALL) ALL
xxx ALL=(ALL:ALL) NOPASSWD:ALL
However, you can view sudo's limitations directly through sudo-l:
$ sudo -l
Matching Defaults entries for xxx on this host:
env_reset, mail_badpass,
secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin
User xxx may run the following commands on this host:
(ALL : ALL) NOPASSWD: ALL
Note that the option Defaults env_reset in the first line means that the environment variables will be reset by default, so that the variables you define will fail in sudo and cannot be retrieved.
In addition, some distributions have an option of Defaults env_keep=""to keep part of the environment variables from being reset, and the variables that need to be reserved are written in double quotes.
Why can sudo echo $var get variable values?
Since sudo execution resets environment variables, why can echo get the corresponding variables?
This is due to the shell command line replacement-reorganization function. When entering the command and pressing Enter, the shell will first cut the command line into fields according to the separator, find out whether there are variables or command substitution for each field, and then reorganize it into new commands, and then execute it.
Therefore, the actual execution of the command is:
$ sudo echo $var # $var => aaa
(sudo echo aaa) # Complete Command Replacement & Reorganization
(echo aaa) # Execution in sudo environment
aaa
Therefore, when the sudo environment is reset, instead of referring to the variable $var, it is echo aaa directly.
Solve
-
sudo -E
- The E option is explained in man page as follows:
-E
The -E (preserve environment) option indicates to the security policy that the user wishes to preserve their existing environment variables. The security policy may return an error if the -E option is specified and the user does not have permission to preserve the environment.
Simply put, with the - E option, the user can retain the existing environment variables of the current user when sudo is executed without being reset by sudo. In addition, if the user does not have permission for the specified environment variables, it will report an error.
Suo-E bash test.sh # with the - E parameter obtains the variable aaa
2. Modify sudo configuration file
In the internal test machine, the security requirement is not high, always need to add - E parameter to execute the script, this security setting is not very convenient, you can modify the configuration to retain the original environment variables through the visudo command, the specific modifications are as follows
$sudo visudo
# Defaults env_reset # Annotate the original configuration
# Defaults env_keep="..." # Comment out the specified variable holder
Defaults! Env_reset# changed to no reset environment
3. Manual addition of variables
Setting the required variables manually in the script may seem cumbersome, or writing the required variables to the beginning of the script to be executed before executing the sudo script.