如何在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$ 

我在做什么错?

源时,将激活脚本加载到活动外壳中。

在脚本中进行操作时,您将其加载到脚本完成时退出的外壳中,然后回到原始的,未激活的外壳。

您最好的选择是在功能中进行

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

或别名

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

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

这是一个示例:

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

在您的外壳上只能这样称呼:

> source venv.sh

或@outmind建议:(请注意,这与ZSH不起作用)

> . venv.sh

您走了,外壳指示将放在您的提示符上。

,尽管它没有添加"(.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

采购在您当前的外壳中运行shell命令。当您像上面这样做的脚本内部源源时,您会影响该脚本的环境,但是当脚本退出时,环境的变化被撤消,因为它们有效地消失了范围。

如果您的意图是在Virtualenv中运行Shell命令,则可以在脚本中在脚本中进行播放。如果您的意图是与Virtualenv内部的外壳进行交互,那么您可以在脚本中产生一个子壳,以继承环境。

是我经常使用的脚本。以$ source script_name

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

您也可以使用子壳更好地包含您的用法来执行此操作 - 以下是一个实际示例:

#!/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"

时,这种样式特别有用
  • commandA/opt/bin下存在不同版本的CC_4
  • commandB存在于系统PATH或非常常见的
  • 这些命令在Virtualenv下失败
  • 一个人需要各种不同的Virtualenvs

为bash脚本采购什么?

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

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

正如其他人已经说过的,您做错了什么不是采购您创建的脚本。当您像显示的脚本一样运行脚本时,它会创建一个新的外壳,该外壳激活虚拟环境然后退出,因此您的原始外壳没有播放脚本的更改。

您需要源脚本,这将使它在当前的外壳中运行。

您可以通过调用source shell.sh. shell.sh

来做到这一点

确保脚本是为了正常执行而不是正常执行的,很高兴在脚本中进行一些检查以提醒您,例如我使用的脚本是:

#!/bin/bash
if [[ "$0" = "$BASH_SOURCE" ]]; then
    echo "Needs to be run using source: . activate_venv.sh"
else
    VENVPATH="venv/bin/activate"
    if [[ $# -eq 1 ]]; then 
        if [ -d $1 ]; then
            VENVPATH="$1/bin/activate"
        else
            echo "Virtual environment $1 not found"
            return
        fi
    elif [ -d "venv" ]; then 
        VENVPATH="venv/bin/activate"
    elif [-d "env"]; then 
        VENVPATH="env/bin/activate"
    fi
    echo "Activating virtual environment $VENVPATH"
    source "$VENVPATH"
fi

它不是防弹的,但很容易理解并完成其工作。

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

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

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

当我学习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

这具有更改提示的优势。

如其他答案中所述,运行脚本时,它会创建一个子壳。当脚本退出时,对该外壳的所有修改将丢失。

实际上是运行虚拟环境处于活动状态的新外壳,而退出它。请注意,这是 new shell,不是在运行脚本之前使用的。这是什么意思是,如果您在其中键入exit,它将从子壳中退出,然后返回前一个(您运行脚本的一个),它不会关闭您的XTERM或其他任何内容,正如您可能预期的那样。

问题是,当我们执行bash时,它会读取其RC文件(/etc/bash.bashrc,〜/.bashrc), Will 更改Shell环境。解决方案是提供像往常一样设置外壳的方法,而 ADDALLALY 激活虚拟环境。为此,我们创建一个临时文件,重新创建原始的狂欢行为,并添加一些启用VENV所需的东西。然后,我们要求Bash使用它而不是通常的RC文件。

拥有新的外壳"专用"的有益副作用对我们的VENV来说,要停用虚拟环境,唯一需要的是退出外壳。我在下面公开的脚本中使用此功能来提供"停用"选项,该选项通过向新壳发送信号(kill -SIGUSR1)来起作用,该信号被截获(trap ...)并引起来自外壳的退出。注意:我使用sigusr1不干扰"正常"中可以设置的任何内容行为。

我使用的脚本:

#!/bin/bash
PYTHON=python3
myname=$(basename "$0")
mydir=$(cd $(dirname "$0") && pwd)
venv_dir="${mydir}/.venv/dev"
usage() {
    printf "Usage: %s (activate|deactivate)n" "$myname"
}
[ $# -eq 1 ] || { usage >&2; exit 1; }
in_venv() {
    [ -n "$VIRTUAL_ENV" -a "$VIRTUAL_ENV" = "$venv_dir" -a -n "$VIRTUAL_ENV_SHELL_PID" ]
}
case $1 in
    activate)
        # check if already active
        in_venv && {
            printf "Virtual environment already activen"
            exit 0
        }
        # check if created
        [ -e "$venv_dir" ] || {
            $PYTHON -m venv --clear --prompt "venv: dev" "$venv_dir" || {
                printf "Failed to initialize venvn" >&2
                exit 1
            }
        }
        # activate
        tmp_file=$(mktemp)
        cat <<EOF >"$tmp_file"
# original bash behavior
if [ -f /etc/bash.bashrc ]; then
    source /etc/bash.bashrc
fi
if [ -f ~/.bashrc ]; then
    source ~/.bashrc
fi
# activating venv
source "${venv_dir}/bin/activate"
# remove deactivate function:
# we don't want to call it by mistake
# and forget we have an additional shell running
unset -f deactivate
# exit venv shell
venv_deactivate() {
    printf "Exitting virtual env shell.n" >&2
    exit 0
}
trap "venv_deactivate" SIGUSR1
VIRTUAL_ENV_SHELL_PID=$$
export VIRTUAL_ENV_SHELL_PID
# remove ourself, don't let temporary files laying around
rm -f "${tmp_file}"
EOF
        exec "/bin/bash" --rcfile "$tmp_file" -i || {
            printf "Failed to execute virtual environment shelln" >&2
            exit 1
        }
    ;;
    deactivate)
        # check if active
        in_venv || {
            printf "Virtual environment not foundn" >&2
            exit 1
        }
        # exit venv shell
        kill -SIGUSR1 $VIRTUAL_ENV_SHELL_PID || {
            printf "Failed to kill virtual environment shelln" >&2
            exit 1
        }
        exit 0
    ;;
    *)
        usage >&2
        exit 1
    ;;
esac

我只需将其添加到我的.bashrc-personal配置文件中。

function sv () {
    if [ -d "venv" ]; then
      source "venv/bin/activate"
    else
      if [ -d ".venv" ]; then
        source ".venv/bin/activate"
      else
        echo "Error: No virtual environment detected!"
      fi
    fi
}

相关内容

  • 没有找到相关文章

最新更新