如何从 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
脚本,即运行其内容就好像它们是您获取它们的外壳或脚本的一部分。 virtualenvironment
的 activate
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
)。我错误地认为它也适用于停用,但这是一种更复杂的情况,因为它是一个仅在运行 workon
或 activate
的 shell 中定义的函数。
【讨论】:
这不适用于普通的virtualenv
或 python3 -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的主要内容,如果未能解决你的问题,请参考以下文章
为啥我不能“停用”pyenv / virtualenv?如何“修复”安装
为什么我不能“停用”pyenv / virtualenv?如何“修复”安装