如何在sudo下使用Python虚拟环境?

我正在尝试在一个不在/home目录下的目录中创建一个与系统环境分离的Python环境(使用virtualenv),因为我需要用它来构建其他需要多个用户访问的软件。我可以成功地创建和激活虚拟环境,但是当我使用sudo执行某些命令(例如制作或编译其他软件)时,会使用系统的Python(通过可用模块可以看出)。
由于在Ubuntu上使用root用户不是一个好习惯,有没有办法告诉sudo使用虚拟环境?或者也许这不是正确的方法,我应该进行全新的Python安装?
我正在使用64位版本的Ubuntu 12.04(和Python 2.7)。

2以下工作是否有效?sudo $(which python) <script> - John Drinane
4个回答

问题几乎可以确定是当你运行sudo时,虚拟环境的环境变量、别名、函数等没有被传递过去。
解决方法是使用sudo显式地运行虚拟环境的Python可执行文件。例如,如果你的虚拟环境是./AwesomeProject,那么你可以运行sudo ./AwesomeProject/bin/python

6你也可以让脚本的第一行指向虚拟环境中的Python二进制文件。#!<virtualenv_dir>/bin/python - OrangeTux
唉,真烦人,到目前为止这是唯一的解决办法。在Mac上,sudo python使用的是虚拟环境中的Python。 - new name
@OrangeTux 我尝试了你建议的方法,但是当我用 sudo python3 my_script.py 运行脚本时它对我不起作用。 - belvederef
在我的情况下,当我使用sudo ./home/pradan/.virtualenvs/sk/bin/python3 main.py时,会出现“命令未找到”的错误。其中main.py是我的脚本文件,而sk是我的虚拟环境的名称。 - Pe Dro

根据您的特定用例,这可能或可能不会解决您的问题,但这里还没有提到。比如说,您想要运行一个已安装在虚拟环境中的Python脚本,并且您需要将其设置为setuid(0),也就是以超级用户身份运行它。假设您的脚本名为myscript.py,那么您可以按照以下方式操作:
(.venv) $ sudo -E env PATH=$PATH ./myscript.py

解释

(.venv) $ 是命令行提示符,您不需要输入它,它只是显示您当前正在使用某个虚拟环境,并且您不是特权用户。

sudo -E 告诉 sudo 在启动进程时需要从当前 shell 环境复制环境变量。因此,如果您在 .venv/bin/activate 脚本中定义了任何额外的变量,则它们应该在您成为 root 用户时保留。

当使用`sudo -E`时,环境变量并不会全部保留,特别是最重要的`PATH`可能会被删除。具体行为取决于您的sudoers文件。然而,这将绕过sudoers文件中的任何设置,因为它会将`PATH`明确地复制到sudo为新进程创建的环境中。这很重要,因为当系统解析您的`myscript.py`中的shebang注释时,它会查找`PATH`变量,并使用第一个符合解释器要求的目录。另一方面,venv会以这样的方式设置shell环境,使得包含所选Python解释器符号链接的目录首先出现,从而导致系统在系统路径上的其他Python之前定位到所需的Python。

刚刚偶然发现了这个问题,对于其他可能遇到同样问题的人来说,Ken是正确的,环境变量没有被传递。我使用的解决方案是将以下行添加到我的脚本中。这样做的额外好处是可以直接从脚本中始终加载虚拟环境。(这意味着您可以在不需要任何其他解决方法的情况下使用crontab或launchd启动脚本。)
base_dir = os.path.dirname(os.path.abspath(__file__))
activate_this = os.path.join(base_dir, 'venv/bin/activate_this.py')
execfile(activate_this, dict(__file__=activate_this))

更多背景信息请参考:https://virtualenv.pypa.io/en/latest/userguide.html#using-virtualenv-without-bin-python

有时候需要更新 $PATH,因为脚本会运行其他程序。例如,pypi-install 需要在 PATH 中找到 py2dsc-deb。以下命令可用:sudo sh -c ". venv/bin/activate; pypi-install $PACKAGE"