如何在Bash脚本中激活virtualenv源

问题:如何在Bash脚本中激活virtualenv源

如何创建Bash脚本来激活Python virtualenv?

我有一个类似的目录结构:

.env
    bin
        activate
        ...other virtualenv files...
src
    shell.sh
    ...my code...

我可以通过以下方式激活我的virtualenv:

user@localhost:src$ . ../.env/bin/activate
(.env)user@localhost:src$

但是,从Bash脚本执行相同操作将不会执行以下操作:

user@localhost:src$ cat shell.sh
#!/bin/bash
. ../.env/bin/activate
user@localhost:src$ ./shell.sh
user@localhost:src$ 

我究竟做错了什么?

How do you create a Bash script to activate a Python virtualenv?

I have a directory structure like:

.env
    bin
        activate
        ...other virtualenv files...
src
    shell.sh
    ...my code...

I can activate my virtualenv by:

user@localhost:src$ . ../.env/bin/activate
(.env)user@localhost:src$

However, doing the same from a Bash script does nothing:

user@localhost:src$ cat shell.sh
#!/bin/bash
. ../.env/bin/activate
user@localhost:src$ ./shell.sh
user@localhost:src$ 

What am I doing wrong?


回答 0

当您获取资源时,您会将激活脚本加载到活动的shell中。

当您在脚本中执行此操作时,将其加载到该外壳中,该外壳将在脚本完成后退出,并且返回到未激活的原始外壳。

最好的选择是在函数中执行此操作

activate () {
  . ../.env/bin/activate
}

或别名

alias activate=". ../.env/bin/activate"

希望这可以帮助。

When you source, you’re loading the activate script into your active shell.

When you do it in a script, you load it into that shell which exits when your script finishes and you’re back to your original, unactivated shell.

Your best option would be to do it in a function

activate () {
  . ../.env/bin/activate
}

or an alias

alias activate=". ../.env/bin/activate"

Hope this helps.


回答 1

您应该使用source调用bash脚本。

这是一个例子:

#!/bin/bash
# Let's call this script venv.sh
source "<absolute_path_recommended_here>/.env/bin/activate"

在您的shell上这样称呼它:

> source venv.sh

或按照@outmind建议:(请注意,这不适用于zsh)

> . venv.sh

到这里,shell指示将出现在您的提示符下。

You should call the bash script using source.

Here is an example:

#!/bin/bash
# Let's call this script venv.sh
source "<absolute_path_recommended_here>/.env/bin/activate"

On your shell just call it like that:

> source venv.sh

Or as @outmind suggested: (Note that this does not work with zsh)

> . venv.sh

There you go, the shell indication will be placed on your prompt.


回答 2

尽管它没有在shell提示符中添加“(.env)”前缀,但我发现此脚本可以按预期工作。

#!/bin/bash
script_dir=`dirname $0`
cd $script_dir
/bin/bash -c ". ../.env/bin/activate; exec /bin/bash -i"

例如

user@localhost:~/src$ which pip
/usr/local/bin/pip
user@localhost:~/src$ which python
/usr/bin/python
user@localhost:~/src$ ./shell
user@localhost:~/src$ which pip
~/.env/bin/pip
user@localhost:~/src$ which python
~/.env/bin/python
user@localhost:~/src$ exit
exit

Although it doesn’t add the “(.env)” prefix to the shell prompt, I found this script works as expected.

#!/bin/bash
script_dir=`dirname $0`
cd $script_dir
/bin/bash -c ". ../.env/bin/activate; exec /bin/bash -i"

e.g.

user@localhost:~/src$ which pip
/usr/local/bin/pip
user@localhost:~/src$ which python
/usr/bin/python
user@localhost:~/src$ ./shell
user@localhost:~/src$ which pip
~/.env/bin/pip
user@localhost:~/src$ which python
~/.env/bin/python
user@localhost:~/src$ exit
exit

回答 3

Sourcing在您当前的shell中运行shell命令。当像上述一样在脚本内部获取源代码时,会影响该脚本的环境,但是当脚本退出时,环境更改将被撤消,因为它们实际上已超出范围。

如果您打算在virtualenv中运行shell命令,则可以在获取激活脚本后在脚本中执行此操作。如果您打算与virtualenv内部的shell进行交互,则可以在脚本内部产生一个继承环境的子shell。

Sourcing runs shell commands in your current shell. When you source inside of a script like you are doing above, you are affecting the environment for that script, but when the script exits, the environment changes are undone, as they’ve effectively gone out of scope.

If your intent is to run shell commands in the virtualenv, you can do that in your script after sourcing the activate script. If your intent is to interact with a shell inside the virtualenv, then you can spawn a sub-shell inside your script which would inherit the environment.


回答 4

这是我经常使用的脚本。运行为$ source script_name

#!/bin/bash -x
PWD=`pwd`
/usr/local/bin/virtualenv --python=python3 venv
echo $PWD
activate () {
    . $PWD/venv/bin/activate
}

activate

Here is the script that I use often. Run it as $ source script_name

#!/bin/bash -x
PWD=`pwd`
/usr/local/bin/virtualenv --python=python3 venv
echo $PWD
activate () {
    . $PWD/venv/bin/activate
}

activate

回答 5

采购bash脚本的目的是什么?

  1. 如果您打算在多个virtualenv之间切换或快速输入一个virtualenv,您是否尝试过virtualenvwrapper?它提供了很多像utils的的workon venvmkvirtualenv venv等等。

  2. 如果您只是在某些virtualenv中运行python脚本,请使用/path/to/venv/bin/python script.py来运行它。

What does sourcing the bash script for?

  1. If you intend to switch between multiple virtualenvs or enter one virtualenv quickly, have you tried virtualenvwrapper? It provides a lot of utils like workon venv, mkvirtualenv venv and so on.

  2. If you just run a python script in certain virtualenv, use /path/to/venv/bin/python script.py to run it.


回答 6

您还可以使用子外壳来更好地包含您的用法-这是一个实际示例:

#!/bin/bash

commandA --args

# Run commandB in a subshell and collect its output in $VAR
# NOTE
#  - PATH is only modified as an example
#  - output beyond a single value may not be captured without quoting
#  - it is important to discard (or separate) virtualenv activation stdout
#    if the stdout of commandB is to be captured
#
VAR=$(
    PATH="/opt/bin/foo:$PATH"
    . /path/to/activate > /dev/null  # activate virtualenv
    commandB  # tool from /opt/bin/ which requires virtualenv
)

# Use the output from commandB later
commandC "$VAR"

此样式在以下情况下特别有用

  • 下的commandAcommandC存在其他版本/opt/bin
  • commandB存在于系统中PATH或非常普遍
  • 这些命令在virtualenv下失败
  • 一个需要各种不同的虚拟环境

You can also do this using a subshell to better contain your usage – here’s a practical example:

#!/bin/bash

commandA --args

# Run commandB in a subshell and collect its output in $VAR
# NOTE
#  - PATH is only modified as an example
#  - output beyond a single value may not be captured without quoting
#  - it is important to discard (or separate) virtualenv activation stdout
#    if the stdout of commandB is to be captured
#
VAR=$(
    PATH="/opt/bin/foo:$PATH"
    . /path/to/activate > /dev/null  # activate virtualenv
    commandB  # tool from /opt/bin/ which requires virtualenv
)

# Use the output from commandB later
commandC "$VAR"

This style is especially helpful when

  • a different version of commandA or commandC exists under /opt/bin
  • commandB exists in the system PATH or is very common
  • these commands fail under the virtualenv
  • one needs a variety of different virtualenvs

回答 7

您应该在一行中使用多个命令。例如:

os.system(". Projects/virenv/bin/activate && python Projects/virenv/django-project/manage.py runserver")

当您在一行中激活虚拟环境时,我认为它会忘记其他命令行,并且可以通过在一行中使用多个命令来防止这种情况。它为我工作:)

You should use multiple commands in one line. for example:

os.system(". Projects/virenv/bin/activate && python Projects/virenv/django-project/manage.py runserver")

when you activate your virtual environment in one line, I think it forgets for other command lines and you can prevent this by using multiple commands in one line. It worked for me :)


回答 8

在学习venv时,我创建了一个脚本来提醒我如何激活它。

#!/bin/sh
# init_venv.sh
if [ -d "./bin" ];then
  echo "[info] Ctrl+d to deactivate"
  bash -c ". bin/activate; exec /usr/bin/env bash --rcfile <(echo 'PS1=\"(venv)\${PS1}\"') -i"
fi

这样做的好处是可以更改提示。

When I was learning venv I created a script to remind me how to activate it.

#!/bin/sh
# init_venv.sh
if [ -d "./bin" ];then
  echo "[info] Ctrl+d to deactivate"
  bash -c ". bin/activate; exec /usr/bin/env bash --rcfile <(echo 'PS1=\"(venv)\${PS1}\"') -i"
fi

This has the advantage that it changes the prompt.