简体   繁体   中英

how to deactivate virtualenv from a bash script

I'm a novice in shell scripting, but I want to make a bash script for activate/deactivate a virtual enviroment using virtualenv. Then I want to use this script like a service in Ubuntu copying it inside /etc/init.d folder.

In my script, I have a variable like this: VENV=/opt/odoo/odoo_server/venv_oddo/bin

This variable represents the bin path in my virtual enviroment.

Inside the script, I can activate the virtual enviroment with this statement: . ${VENV}/activate . ${VENV}/activate

This is possible because activate is a file inside bin directory in the virtual enviroment.

But I don't know the statement to use in my script to deactivate my virtual enviroment. I can't do this: . ${VENV}/deactivate . ${VENV}/deactivate

The problem is that doesn't exist a file named deactivate, but deactivated is a function inside the bin/activate file in the virtual enviroment.

Just deactivate . It will work in the script as well as in command line, as long as you're using bash.

Edit: also in most cases it is a better idea to spell full python path in your scripts and services. It is stateless, more portable and works pretty much everywhere. So instead of doing

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

it is usually preferable to do

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

Trust me, it will save you debugging time)

It'll be hard to make a service like that useful.

. ${VENV}/activate # note the dot

or

source ${VENV}/activate

will source the activate script, ie run its contents as if they were part of the shell or script where you source them . virtualenvironment 's activate is designed for this usage . In contrast, just executing the script normally with

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

will run its content in a subshell and won't have any useful effect.

However, your service script will already run in a subshell of its own. So except for any python commands you run as part of the service start process, it won't have any effect.

On the plus side, you won't even have to care about de-activating the environment, unless you want to run even more python stuff in the service start process, but outside of your virtualenv.

The deactivate "command" provided by virtualenvwrapper is actually a shell function, likewise so for workon . If you have a virtual env active, you can list the names of these functions with typeset -F .

In order to use them in a script, they need to be defined there, because shell functions do not propagate to child shells.

To define these functions, source the virtualenvwrapper.sh script in the shell script where you intend to invoke these functions, eg:

source $(which virtualenvwrapper.sh)

That allows you to invoke these functions in your shell script like you would do in the shell:

deactivate

Update: What I described works for the other functions provided by virtualenvwrapper (eg workon ). I incorrectly assumed it would work also for deactivate, but that one is a more complicated case, because it is a function that will be defined only in the shell where workon or activate was run.

copy deactivate code in ${VENV}/activate.

paste your ~/.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
}

run command.

$ $VENV/activate
$ deactivate

I have selectively used without problems python 2.7 and python 3.5 in this way.

I want to know the reason for the negative evaluation.

Use below :

declare -Ff deactivate  && deactivate

Since the deactivate function created by sourcing ~/bin/activate cannot be discovered by the usual means of looking for such a command in ~/bin, you may wish to create one that just executes the function deactivate.

The problem is that a script named deactivate containing a single command deactivate will cause an endless loop if accidentally executed while not in the venv. A common mistake.

This can be avoided by only executing deactivate if the function exists (ie has been created by sourcing activate).

If you only need to programatically disable / change virtualenv, you can use a shell function instead of a shell script . For example, put at the end of your ~/.bashrc or ~/.bash_aliases (if you have it set up) or ~/.zshrc or ~/.zsh_aliases (if you use 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

}

Restart the shell or re-source the file you changed with source ~/.zsh_aliases and use the command ch to execute the function.

Somehow deactivate also can't be found in my case (usually I work under far2l inside bash ). I use the solution:

unset VIRTUAL_ENV & deactivate

After that pip -V is showing path in .local .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM