如何从 bash 脚本中停用 virtualenv

Posted

技术标签:

【中文标题】如何从 bash 脚本中停用 virtualenv【英文标题】:how to deactivate virtualenv from a bash script 【发布时间】:2015-06-15 05:44:50 【问题描述】:

我是 shell 脚本的新手,但我想使用 virtualenv 制作一个用于激活/停用虚拟环境的 bash 脚本。 然后我想将此脚本用作 Ubuntu 中的服务,将其复制到 /etc/init.d 文件夹中。

在我的脚本中,我有一个这样的变量: VENV=/opt/odoo/odoo_server/venv_oddo/bin

这个变量代表我的虚拟环境中的 bin 路径。

在脚本内部,我可以使用以下语句激活虚拟环境: . $VENV/activate

这是可能的,因为 activate 是虚拟环境中 bin 目录中的一个文件。

但我不知道要在我的脚本中使用什么语句来停用我的虚拟环境。 我不能这样做:. $VENV/deactivate

问题是不存在名为deactivate的文件,但deactivate是虚拟环境中bin/activate文件中的一个函数。

【问题讨论】:

如果您的脚本在子进程中运行,则当脚本存在时,virtualenv 将不复存在。在退出前显式调用deactivate 既没必要也没用。 【参考方案1】:

只需deactivate。只要您使用 bash,它就可以在脚本和命令行中运行。

编辑:在大多数情况下,最好在脚本和服务中拼写完整的 python 路径。它是无状态的,更便携,几乎可以在任何地方使用。所以不要这样做

. $VENV/bin/activate
/path/to/my/script.py --parameters

通常最好这样做

$VENV/bin/python /path/to/my/script --parameters

相信我,它会为您节省调试时间)

【讨论】:

感谢您的回答,但如果我在 bash 脚本中使用 deactivate,则在执行它时,我会在 shell 中收到以下消息:deactivate: command not found 你不能在 shell 脚本中使用deactivate,除非先找到定义这个函数的脚本。请参阅我对这个问题的单独回答。【参考方案2】:

这样的服务很难发挥作用。

. $VENV/activate # note the dot

source $VENV/activate

将source activate 脚本,即运行其内容就好像它们是您获取它们的外壳或脚本的一部分virtualenvironmentactivate is designed for this usage。相反,只需正常执行脚本即可

$VENV/activate # note: NO dot and NO 'source' command

将在子shell中运行其内容,不会产生任何有用的效果。

但是,您的服务脚本已经在其自己的子 shell 中运行。因此,除了您作为服务启动过程的一部分运行的任何 python 命令外,它不会有任何影响。

从好的方面来说,你甚至不必关心停用环境,除非你想在服务启动过程中运行更多的 python 东西,但在你的 virtualenv 之外。

【讨论】:

谢谢你的回答,但我不明白你说的是:正常执行脚本(这样它的内容会在子shell中运行)不会有任何有用的效果. 我已经编辑了我的答案。 @edkalel,现在更容易理解了吗?关键是activate 只影响其来源的 shell/脚本,而不是整个系统。 感谢您的解释。我想我已经明白了。然后,如果我在我的 bash 脚本中使用 activate(带有 . 或源代码),则虚拟环境将仅在脚本内部被激活,而不是在 shell 外部。【参考方案3】:

复制 $VENV/activate 中的停用代码。

粘贴你的 ~/.bashrc

deactivate() 
    # reset old environment variables
    if [ -n "$_OLD_VIRTUAL_PATH" ] ; then
        PATH="$_OLD_VIRTUAL_PATH"
        export PATH
        unset _OLD_VIRTUAL_PATH
    fi
    if [ -n "$_OLD_VIRTUAL_PYTHONHOME" ] ; then
        PYTHONHOME="$_OLD_VIRTUAL_PYTHONHOME"
        export PYTHONHOME
        unset _OLD_VIRTUAL_PYTHONHOME
    fi

    # This should detect bash and zsh, which have a hash command that must
    # be called to get it to forget past commands.  Without forgetting
    # past commands the $PATH changes we made may not be respected
    if [ -n "$BASH" -o -n "$ZSH_VERSION" ] ; then
        hash -r
    fi

    if [ -n "$_OLD_VIRTUAL_PS1" ] ; then
        PS1="$_OLD_VIRTUAL_PS1"
        export PS1
        unset _OLD_VIRTUAL_PS1
    fi

    unset VIRTUAL_ENV
    if [ ! "$1" = "nondestructive" ] ; then
        # Self destruct!
        unset -f deactivate
    fi

运行命令。

$ $VENV/activate
$ deactivate

我有选择地以这种方式使用没有问题的python 2.7和python 3.5。

我想知道负面评价的原因。

【讨论】:

我认为缺点是因为(1)这个解决方案不干净,(2)它不能直接解决提到的问题。通常 .bashrc 仅用于交互式 shell,而问题是用于 bash 脚本。但我没有看到任何真正干净的解决方案。 UPD:它不起作用,因为 _OLD_VIRTUAL_PATH 是一个局部变量而不是导出的......唉。没有好的解决办法。根本没有解决办法。【参考方案4】:

virtualenvwrapper提供的deactivate“命令”实际上是一个shell函数,workon也是如此。如果您有一个激活的虚拟环境,您可以使用typeset -F 列出这些函数的名称。

为了在脚本中使用它们,需要在其中定义它们,因为 shell 函数不会传播到子 shell。

要定义这些函数,请在要调用这些函数的 shell 脚本中获取 virtualenvwrapper.sh 脚本,例如:

source $(which virtualenvwrapper.sh)

这使您可以像在 shell 中一样在 shell 脚本中调用这些函数:

deactivate

更新:我所描述的适用于 virtualenvwrapper 提供的其他功能(例如workon)。我错误地认为它也适用于停用,但这是一种更复杂的情况,因为它是一个仅在运行 workonactivate 的 shell 中定义的函数。

【讨论】:

这不适用于普通的 virtualenvpython3 -m venv 可能不得不使用brasizy的方法(虽然我不喜欢它)。实际上我认为通常只恢复 $PATH 就足够了。【参考方案5】:

如果您只需要以编程方式禁用/更改 virtualenv,则可以使用 shell 函数而不是 shell 脚本。例如,放在~/.bashrc~/.bash_aliases(如果您已设置)或~/.zshrc~/.zsh_aliases(如果您使用zsh)的末尾:

function ch() 

  # change this to your directory
  cd ~/git-things/my_other_py_project

  # this works, as a shell function won't spawn a subshell as the script would
  deactivate

  # re-source to change the virtualenv (my use case; change to fit yours)
  source .venv-myotherpyproject/bin/activate


重新启动 shell 或使用 source ~/.zsh_aliases 重新获取您更改的文件并使用命令 ch 执行该功能。

【讨论】:

【参考方案6】:

在我的情况下也找不到deactivate(通常我在 bash 内的 far2l 下工作)。我使用解决方案:

unset VIRTUAL_ENV & deactivate

之后pip -V.local中显示路径。

【讨论】:

以上是关于如何从 bash 脚本中停用 virtualenv的主要内容,如果未能解决你的问题,请参考以下文章

在 Makefile 上停用 virtualenv

如何离开/退出/停用Python virtualenv

为啥我不能“停用”pyenv / virtualenv?如何“修复”安装

为什么我不能“停用”pyenv / virtualenv?如何“修复”安装

无法在 Jupyter notebook python 中停用 virtualenv

如何从 virtualenv 中的 python 脚本运行 Tensorboard?