切换用户时如何设置环境

4 投票
2 回答
2281 浏览
提问于 2025-04-16 03:04

我有一个用bash写的备份脚本,它以root身份运行(通过cron定时任务),这个脚本会把一些特定的任务交给其他不同用户拥有的bash脚本去执行。(简单来说,有些事情必须以root身份做,而不同的任务则交给拥有合适环境的用户去完成,比如oracle、amazon等)

mkdir -p /tmp/backup$NAME
su - oracle -c "~/.backups/export-test.sh"
tar cf /tmp/backup/$NOW.tar /tmp/backup$NAME
su - amazon upload_to_amazon.sh /tmp/backup/$NOW.tar

这个脚本本身会以oracle用户的身份执行一些任务:

mkdir -p $TMP_LOCATION
cd ~/.backups
exp $TMP_LOCATION/$NAME-$NOW

当我尝试用python模拟这个行为时,我写出了以下代码(同样是以root身份通过cron启动的)

name = "oracle"

# part run as root
os.makedirs(tmp_backup + name)


os.setegid(pwd.getpwnam(name)[3])
os.seteuid(pwd.getpwnam(name)[2])

# part run as oracle
os.makedirs(tmp_location)
os.chdir(os.path.expanduser("~{user}/.backups".format(user=name)))
subprocess.check_call(["exp",
                       "os.path.join(tmp_location, name+'-'+now)"
                      ])

在bash中使用su -时,会启动一个新的shell,并且会设置那个用户的所有环境变量。
我该如何改进我的python脚本呢?有没有什么标准的方法可以参考?我在想环境变量、umask等等……

环境是Solaris,如果这有影响的话。

2 个回答

0

我可以以管理员身份运行亚马逊的服务,而且不需要设置环境变量。为了实现这一点,我使用了boto这个工具。

至于我用到的Oracle环境变量,我使用了这段代码:

if "ORACLE_HOME" not in os.environ or os.environ["ORACLE_HOME"] != ORACLE_HOME:
    logger.debug("setting ORACLE_HOME='{oh}'".format(oh=ORACLE_HOME))
    os.environ['ORACLE_HOME'] = ORACLE_HOME
if ORACLE_HOME + "/bin" not in os.environ["PATH"].split(":"):
    logger.debug("setting PATH='{p}'".format(p=os.path.expandvars(ORACLE_PATH)))
    os.environ['PATH'] = os.path.expandvars(ORACLE_PATH)
if "NLS_LANG" not in os.environ or os.environ["NLS_LANG"] != NLS_LANG:
    logger.debug("setting NLS_LANG='{n}'".format(n=NLS_LANG))
    os.environ['NLS_LANG'] = NLS_LANG
1

该用户的所有环境变量都已设置。

通常是因为当一个命令行窗口启动时,它会运行一个叫做 .profile 的文件。

你有几种选择:

  1. 使用 subprocess.Popen 创建一个合适的子进程来执行这个 shell 的 .profile 文件,这和 su - 的效果是一样的。

  2. 仔细找到环境变量的设置,并在 Python 中模仿这些设置。问题是 .profile 文件可能会做很多复杂的事情,所以要准确了解它的具体影响可能会有点麻烦。

  3. 或者你可以提取出相关的环境变量,让它们在 shell 环境和你的 Python 程序中都能使用。

首先,查看每个用户的 .profile 文件,弄清楚它设置了哪些环境变量(这些和别的像别名或其他不适用于你的 Python 脚本的内容是不同的)。其中一些环境变量与你运行的脚本有关,而有些则无关。

其次,把“相关”的环境变量整理成一个整洁的 env_backups.sh 脚本或 env_uploads.sh 脚本。

一旦你有了这些环境变量的脚本,更新你的 .profile 文件,用 source env_backup.shsource env_uploads.sh 来替换环境变量的设置。

第三,在运行 Python 程序之前,先执行相关的 env_thisenv_that 脚本。这样你的 Python 环境就能和 shell 环境共享这些变量,而且你只需要在一个地方维护它们。

my_script.sh

source ~oracle/env_backup.sh
source ~amazon/env_uploads.sh
python my_script.py

我觉得这样做最好。(因为我们就是这么做的。)

撰写回答