programing

Bash 스크립트에서 virtualenv 활성화를 소스하는 방법

oldcodes 2023. 5. 9. 23:00
반응형

Bash 스크립트에서 virtualenv 활성화를 소스하는 방법

Python virtualenv를 활성화하기 위해 Bash 스크립트를 어떻게 생성합니까?

디렉터리 구조는 다음과 같습니다.

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

다음을 통해 가상 환경을 활성화할 수 있습니다.

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

소스는 현재 셸에서 셸 명령을 실행합니다.위와 같이 스크립트 내부를 소스화하면 해당 스크립트의 환경에 영향을 미치지만 스크립트가 종료되면 환경 변경이 실제로 범위를 벗어났기 때문에 실행 취소됩니다.

가상 환경에서 셸 명령을 실행하려는 경우 활성화 스크립트를 소스한 후 스크립트에서 이를 수행할 수 있습니다.가상 환경 내부의 셸과 상호 작용하려는 경우 스크립트 내부에 환경을 상속하는 하위 셸을 생성할 수 있습니다.

여기 제가 자주 사용하는 스크립트가 있습니다.다음으로 실행$ 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또는commandC아래에 존재합니다./opt/bin
  • commandB합니다.PATH또는 매우 일반적입니다.
  • 이러한 명령은 가상 환경에서 실패합니다.
  • 다양한 가상 환경이 필요합니다.

bash 스크립트를 소싱하는 용도는 무엇입니까?

  1. 여러 가상 환경 간에 전환하거나 하나의 가상 환경을 빠르게 입력하려는 경우 시도해 보셨습니까?virtualenvwrapper다음과 같은 많은 유용성을 제공합니다.workon venv,mkvirtualenv venv등등.

  2. 에는 특정가환파스실경행우는하를을 합니다./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

이렇게 하면 프롬프트가 변경된다는 장점이 있습니다.

다른 답변에서 설명한 것처럼 스크립트를 실행하면 하위 셸이 생성됩니다.스크립트가 종료되면 해당 셸에 대한 모든 수정 내용이 손실됩니다.

실제로 가상 환경이 활성화된 곳에서 새 셸을 실행하고 이 셸을 종료하지 않는 것이 필요합니다.이 셸은 셸이지 스크립트를 실행하기 전에 사용 중인 셸이 아닙니다.이것이 의미하는 것은, 만약 당신이 입력한다면.exit그 안에서 하위 셸을 종료하고 이전 셸(스크립트를 실행한 셸)으로 돌아갑니다. 예상했던 것처럼 xterm이나 다른 어떤 것도 닫히지 않습니다.

문제는 bash를 실행할 때 rc 파일(/etc/bash.bashrc, ~/.bashrc)을 읽어 셸 환경을 변경한다는 것입니다.솔루션은 가상 환경을 추가로 활성화하는 동시에 평소처럼 셸을 설정할 수 있는 방법을 bash에 제공하는 것입니다.이를 위해 임시 파일을 생성하여 원래 bash 동작을 다시 생성하고 venv를 활성화하는 데 필요한 몇 가지 사항을 추가합니다.그런 다음 일반적인 rc 파일 대신 사용하도록 bash에 요청합니다.

새로운 셸이 Venv 전용으로 "전용"되면 가상 환경을 비활성화하기 위해 필요한 것은 셸을 종료하는 것뿐입니다.에서 이것을 셸shell)에을 제공합니다.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 active\n"
            exit 0
        }

        # check if created
        [ -e "$venv_dir" ] || {
            $PYTHON -m venv --clear --prompt "venv: dev" "$venv_dir" || {
                printf "Failed to initialize venv\n" >&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 shell\n" >&2
            exit 1
        }
    ;;
    deactivate)
        # check if active
        in_venv || {
            printf "Virtual environment not found\n" >&2
            exit 1
        }

        # exit venv shell
        kill -SIGUSR1 $VIRTUAL_ENV_SHELL_PID || {
            printf "Failed to kill virtual environment shell\n" >&2
            exit 1
        }
        exit 0
    ;;
    *)
        usage >&2
        exit 1
    ;;
esac

저는 이것을 제 .bashrc-personal config 파일에 간단히 추가했습니다.

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
}

언급URL : https://stackoverflow.com/questions/13122137/how-to-source-virtualenv-activate-in-a-bash-script

반응형