Como originar a ativação do virtualenv em um script Bash

97

Como você cria um script Bash para ativar um Python virtualenv?

Eu tenho uma estrutura de diretório como:

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

Posso ativar meu virtualenv por:

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

No entanto, fazer o mesmo a partir de um script Bash não faz nada:

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

O que estou fazendo de errado?

Cerin
fonte
6
Quando você executa um script de shell, na verdade está criando um novo shell. O objetivo de usar sourceé mudar algo no shell atual. Você pode usar o python do virtualenv usando o caminho completo ./env/bin/python.
Pablo Navarro
@NgureNyaga, Não, essa pergunta não é a mesma que a minha. Eles estão perguntando como obter a fonte de um local arbitrário. Eu já sei fazer isso. Estou perguntando como fonte em um script bash personalizado e manter a fonte.
Cerin

Respostas:

76

Ao fazer o código, você está carregando o script de ativação em seu shell ativo.

Quando você faz isso em um script, você o carrega naquele shell que sai quando o script termina e você volta ao shell original não ativado.

Sua melhor opção seria fazê-lo em uma função

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

ou um pseudônimo

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

Espero que isto ajude.

richo
fonte
para windows c: \ tutorial>. \ env \ Scripts \ activate
max4ever
5
Eu não tinha absolutamente nenhuma ideia do que estava acontecendo quando eu fiz a fonte. Isso mudou muito meu script bash para melhor. Obrigado!
Robert Townley
1
Sua ideia de apelido funcionou bem para mim também. Apenas uma observação: eu tive que colocá-lo (alias abcdef = "source ... / bin / activate") no meu script .zshrc (ou .bashrc para os usuários do bash) para que funcionasse.
Shahins
Esta é uma boa solução se você tiver seu virtualenvs usando o nome de pasta padrão. Eu tinha mais de um repo na pasta, bagunçando o virtualenvs. Mudei para esse padrão agora.
3manuek
3
Eu sou muito novo no bash etc. Você pode expandir este exemplo para que ele mostre o script completo?
AljoSt
54

Você deve chamar o script bash usando o código-fonte.

Aqui está um exemplo:

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

Em seu shell, basta chamá-lo assim:

> source venv.sh

Ou como @outmind sugeriu: (observe que isso não funciona com zsh)

> . venv.sh

Pronto, a indicação do shell será colocada em seu prompt.

Flavio Garcia
fonte
2
ou mesmo apenas ". venv.sh"
outmind
não importa o que eu tente, isso source "/home/surest/Desktop/testservers/TEST_VENV/venv3/bin/activate"produz:/home/surest/Desktop/testservers/TEST_VENV/py3.sh: 10: /home/surest/Desktop/testservers/TEST_VENV/py3.sh: source: not found
Também não recebo nada quando digito which sourceem um prompt do shell, mas source venv3/bin/activatefaço o que espero e abro o venv. ...
Por que isso funciona, mas source ./env/bin/activate(com o mesmo #!/bin/bashprefixo) não? Qual é a diferença entre usar aspas e não usar?
blacksite
Não tenho nenhum problema em usar o código-fonte dentro do script sem aspas. Eu vejo um problema com source ./env/bin/activateporque isso é relativo ao caminho que você está executando certo? Se você alterar o diretório dentro do script, poderá ficar relativo.
Flavio Garcia
13

Embora não adicione o prefixo "(.env)" ao prompt do shell, descobri que esse script funciona conforme o esperado.

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

por exemplo

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
Cerin
fonte
5
tecnicamente, você está gerando uma subcamada. Não é necessariamente um problema, mas você deve explicitar isso para o OP.
richo
Funcionou, mas eu tive que dar permissão para o meu arquivo "ativar" antes.
Adrian Lopez
1
Isso funciona em 2019! Em macos eu só tive que mudar o /bin/bashpara/usr/bin/env bash
valem
Funciona no Ubuntu 18.04 AWS EC2 em 2020. Gostaria de saber como faço para desativar usando a mesma lógica?
CSF Junior
Você deactivatedo subshell com exitou Ctrl + d
Alexx Roche
10

Sourcing executa comandos shell em seu shell atual. Quando você fornece dentro de um script como está fazendo acima, está afetando o ambiente para aquele script, mas quando o script é encerrado, as mudanças no ambiente são desfeitas, pois efetivamente saíram do escopo.

Se sua intenção é executar comandos shell no virtualenv, você pode fazer isso em seu script após obter o script de ativação. Se sua intenção é interagir com um shell dentro do virtualenv, você pode gerar um sub-shell dentro de seu script que herdaria o ambiente.

zigg
fonte
2

Aqui está o script que uso com frequência. Execute como$ source script_name

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

activate
Sand1512
fonte
1

Para que serve a fonte do script bash?

  1. Se você pretende alternar entre vários virtualenvs ou entrar em um virtualenv rapidamente, já tentou virtualenvwrapper? Ele fornece muitos utilitários como workon venv, mkvirtualenv venve assim por diante.

  2. Se você acabou de executar um script python em determinado virtualenv, use /path/to/venv/bin/python script.pypara executá-lo.

iMom0
fonte
Na verdade, gostaria de chamar workon ...de um script bash. (Porque quero executar mais coisas depois, toda vez que ele for inicializado). No entanto, não consigo encontrar uma maneira de fazê-lo funcionar.
Daniel B.
1

Você também pode fazer isso usando um subshell para melhor conter seu uso - aqui está um exemplo prático:

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

Este estilo é especialmente útil quando

  • uma versão diferente commandAou commandCexiste em/opt/bin
  • commandBexiste no sistema PATHou é muito comum
  • esses comandos falham no virtualenv
  • é preciso uma variedade de ambientes virtuais diferentes
ti7
fonte
Não se esqueça de aspas duplas $(...)ou você perderá os espaços e tabulações contidos na saída.
Eric
"${VAR}"é estritamente equivalente a "$VAR"você não precisa de chaves em torno de variáveis ​​de shell porque as aspas duplas são realmente mais poderosas. A exceção é ao usar modificadores como por exemplo"${VAR:-default_value}"
Eric
PATH=$PATH:/opt/binprecisa de cotação adequada para lidar com caminhos com espaços e tabulações.
Eric
@Eric Obrigado, mas você pode usar o editbotão abaixo das postagens para sugerir mudanças nelas! Além disso, é importante saber que, embora seja frequentemente um requisito e importante para a segurança, qualquer pessoa que adicionar IFSchars a intencionalmente PATHé um terrorista.
ti7
0

Você deve usar vários comandos em uma linha. por exemplo:

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

quando você ativa seu ambiente virtual em uma linha, acho que ele esquece as outras linhas de comando e você pode evitar isso usando vários comandos em uma linha. Funcionou para mim :)

Ahmadreza Pourghodrat
fonte
0

Quando eu estava aprendendo venv, criei um script para me lembrar como ativá-lo.

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

Isso tem a vantagem de alterar o prompt.

Alexx Roche
fonte