如何在 su - 中保留环境变量?

如何在 su - 中保留环境变量?

当使用 ssh 到远程系统时,我导出LC_ALL="en_US.UTF-8"(通过sendEnvssh_config )。当我su - user123登录 shell 重置此变量时。LC_xxx当以远程系统上的另一个用户身份执行登录 shell 时,是否有办法保留此变量(以及其他变量)?

我意识到我可以在执行 shell 或目标用户的条目后手动导出变量~/.bashrc,但是如果可能的话,我宁愿尝试保留发送的原始值ssh。谢谢。

编辑:我确实需要初始化用户环境的特定部分,这就是su -使用的原因。我只想保存LC_xxx

答案1

我发现和su的实现(以及 GNU 的实现,尽管最终从 coreutils 中删除)有一个保留环境的选项:util-linuxshadow-utilscoreutilssu

-m, -p, --preserve-environment
           Preserve the current environment, except for:
...

其他系统可能有-m(如 BSD),或者-p两者都有,或者没有。 Busyboxsu具有-m-p。玩具盒su(Android) 有-p.

这样,目标用户的 shell 初始化文件就会被执行,就像登录 shell 一样,但任何LC_xxx变量都可以被测试,但如果它们已经包含有效值,则不会被初始化。

编辑:请注意,我可以通过添加一个/etc/profile.d/ssh_lc_vars.sh处理导出的 LC_xxx 变量的脚本来在系统范围内应用此功能。我还必须对未初始化的环境变量做一些额外的工作,这些变量不能用su -ml userxxx.下面是更多示例,因为我无法包含整个脚本。如果有人可以改进它,那就更好了。

...
# clean up client-side variable for junk
lc_sanitize()
{
   arg="$1"
   # first, strip underscores
   clean="${arg//_/}"

   # next, replace spaces with underscores
   clean="${clean// /_}"

   # now, clean out anything that's not alphanumeric, underscore, hypen or dot
   ret="${clean//[^a-zA-Z0-9_\.-]/}"

   # return santized value to caller
   echo "$ret"
}

# LC_MY_LANG comes from an ssh client environment. If empty,
# this isn't a remote ssh user, but set it locally so this user
# can connect elsewhere where this script runs
if [ -z "$LC_MY_LANG" ]; then
   # force an LC_xxx setting for the environment
    LC_MY_LANG="en-US.utf-8"
else
    # otherwise, use the LC_xxxx variable from the ssh environment
    # 2017-01-30 - when using "su --preserve-environment  userxxx --login" be sure to fixup needed variables
    # shorthand: su -ml user111
    export USER=`whoami`
    export LOGNAME=${USER}
    export HOME=$( getent passwd "$USER" | cut -d: -f6 )
    cd ${HOME}

    # sanitize variable which was set client-side and log it
    u_sanitized=$(lc_sanitize "$LC_MY_LANG")
    echo "Notice: LC_MY_LANG sanitized to $u_sanitized from $SSH_CLIENT as user $USER" | logger -p auth.info
fi

# mark variable read-only so user cannot change it then export it
readonly LC_MY_LANG
# set terminal to LC_MY_LANG
export LC_LANG=${LC_MY_LANG}
export LC_MY_LANG
...

答案2

跳过-su的参数。

   -, -l, --login
       Provide an environment similar to what the user would expect had
       the user logged in directly.

答案3

以下内容对我有用,这相当于调用一个额外的 shell,该 shell 将用于运行设置环境变量的命令。

# LC_ALL is set in parent shell
> export LC_ALL=C
> env | grep LC_ALL
LC_ALL=C

# Verify that since we use `su -` the LC_ALL is not preserved
> su - user123 -c '/bin/bash'
user123@026aedc05a97:~$ env | grep LC_ALL
user123@026aedc05a97:~$ exit

# Pass the variable to the extra shell explicitly
> su - user123 -c 'LC_ALL='$LC_ALL' /bin/bash'
# The variable is now set
user123@026aedc05a97:~$ env | grep LC_ALL
LC_ALL=C
user123@026aedc05a97:~$

相关内容