Comment activer virtualenv dans un script Bash

98

Comment créer un script Bash pour activer un virtualenv Python?

J'ai une structure de répertoires comme:

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

Je peux activer mon virtualenv en:

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

Cependant, faire la même chose à partir d'un script Bash ne fait rien:

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

Qu'est-ce que je fais mal?

Cerin
la source
6
Lorsque vous exécutez un script shell, vous créez en fait un nouveau shell. Le but de l'utilisation sourceest de changer quelque chose dans le shell actuel. Vous pouvez utiliser le python de virtualenv en utilisant le chemin complet ./env/bin/python.
Pablo Navarro
@NgureNyaga, Non, cette question n'est pas la même que la mienne. Ils demandent comment s'approvisionner à partir d'un emplacement arbitraire. Je sais déjà comment faire cela. Je demande comment se procurer dans un script bash personnalisé et maintenir la source.
Cerin

Réponses:

79

Lorsque vous vous approvisionnez, vous chargez le script d'activation dans votre shell actif.

Lorsque vous le faites dans un script, vous le chargez dans ce shell qui se termine lorsque votre script se termine et que vous êtes de retour à votre shell d'origine non activé.

Votre meilleure option serait de le faire dans une fonction

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

ou un alias

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

J'espère que cela t'aides.

richo
la source
pour windows c: \ tutorial>. \ env \ Scripts \ activate
max4ever
6
Je n'avais absolument aucune idée de ce qui se passait quand je fais des sources. Cela a considérablement changé mon script bash pour le mieux. Je vous remercie!
Robert Townley
1
Votre idée d'alias a bien fonctionné pour moi aussi. Juste une note: j'ai dû le mettre (alias abcdef = "source ... / bin / activate") dans mon script .zshrc (ou .bashrc pour les utilisateurs bash) pour que cela fonctionne.
shahins
C'est une bonne solution si vos virtualenvs utilisent le nom de dossier par défaut. J'avais l'habitude d'avoir plus d'un repo dans le dossier, ce qui faisait un désordre sur les virtualenvs. Je suis maintenant passé à cette valeur par défaut.
3manuek
3
Je suis tout à fait nouveau dans bash etc. Pouvez-vous développer cet exemple pour qu'il montre le script complet?
AljoSt
57

Vous devez appeler le script bash en utilisant source.

Voici un exemple:

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

Sur votre shell, appelez-le comme ça:

> source venv.sh

Ou comme @outmind l'a suggéré: (Notez que cela ne fonctionne pas avec zsh)

> . venv.sh

Là vous allez, l'indication shell sera placée sur votre invite.

Flavio Garcia
la source
2
ou même juste ". venv.sh"
déjouer le
peu importe ce que j'essaye, cela source "/home/surest/Desktop/testservers/TEST_VENV/venv3/bin/activate"produit:/home/surest/Desktop/testservers/TEST_VENV/py3.sh: 10: /home/surest/Desktop/testservers/TEST_VENV/py3.sh: source: not found
Je n'obtiens rien non plus lorsque je tape which sourceà l'invite du shell, mais source venv3/bin/activatefait ce que j'attends et ouvre le venv. ...
Pourquoi cela fonctionne-t-il, mais pas source ./env/bin/activate(avec le même #!/bin/bashpréfixe)? Quelle est la différence entre utiliser des guillemets et non?
blacksite
Je n'ai aucun problème à utiliser la source à l'intérieur du script sans guillemets. Je vois un problème avec source ./env/bin/activateparce que cela est relatif au chemin que vous utilisez, n'est-ce pas? Si vous modifiez le répertoire à l'intérieur du script, vous pouvez devenir relatif.
Flavio Garcia
13

Bien qu'il n'ajoute pas le préfixe "(.env)" à l'invite du shell, j'ai trouvé que ce script fonctionne comme prévu.

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

par exemple

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
la source
5
techniquement, vous créez un sous-shell. Ce n'est pas nécessairement un problème, mais vous devriez le préciser pour le PO.
richo
Cela a fonctionné, mais j'ai dû donner la permission à mon fichier «activer» avant.
Adrian Lopez
1
Cela fonctionne en 2019! Sur macos, je devais juste changer le /bin/bashen/usr/bin/env bash
valem
Fonctionne dans Ubuntu 18.04 AWS EC2 en 2020. Je me demande comment désactiver en utilisant la même logique?
CSF Junior
Vous deactivatedu sous-shell avec exitou Ctrl + d
Alexx Roche
10

Le sourcing exécute des commandes shell dans votre shell actuel. Lorsque vous vous approvisionnez à l'intérieur d'un script comme vous le faites ci-dessus, vous affectez l'environnement de ce script, mais lorsque le script se termine, les changements d'environnement sont annulés, car ils sont effectivement sortis de la portée.

Si votre intention est d'exécuter des commandes shell dans virtualenv, vous pouvez le faire dans votre script après avoir extrait le script d'activation. Si votre intention est d'interagir avec un shell à l'intérieur de virtualenv, vous pouvez alors générer un sous-shell dans votre script qui hériterait de l'environnement.

zigg
la source
2

Voici le script que j'utilise souvent. Exécutez-le comme$ source script_name

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

activate
Sable1512
la source
1

À quoi sert le sourcing du script bash?

  1. Si vous avez l'intention de basculer entre plusieurs virtualenv ou d'entrer rapidement un virtualenv, avez-vous essayé virtualenvwrapper? Il fournit de nombreux outils comme workon venv, mkvirtualenv venvetc.

  2. Si vous exécutez simplement un script python dans certains virtualenv, utilisez /path/to/venv/bin/python script.pypour l'exécuter.

iMom0
la source
En fait, je voudrais appeler à workon ...partir d'un script bash. (Parce que je veux exécuter d'autres choses par la suite à chaque fois au démarrage.) Je ne trouve pas de moyen de le faire fonctionner, cependant.
Daniel B.
1

Vous pouvez également le faire en utilisant un sous-shell pour mieux contenir votre utilisation - voici un exemple pratique:

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

Ce style est particulièrement utile lorsque

  • une version différente de commandAou commandCexiste sous/opt/bin
  • commandBexiste dans le système PATHou est très courant
  • ces commandes échouent sous virtualenv
  • on a besoin d'une variété de virtualenvs différents
ti7
la source
N'oubliez pas de double guillemet le $(...)ou il vous manquera des espaces et des tabulations contenus dans la sortie.
Eric
"${VAR}"est strictement équivalent au fait que "$VAR"vous n'avez pas besoin de parenthèses autour des variables shell car les guillemets doubles sont en fait plus puissants. L'exception est lors de l'utilisation de modificateurs comme par exemple"${VAR:-default_value}"
Eric
PATH=$PATH:/opt/bina besoin de citations appropriées pour gérer les chemins avec des espaces et des tabulations.
Eric
@Eric Merci, mais vous pouvez utiliser le edit bouton ci-dessous pour leur suggérer des changements! De plus, sachez que même si c'est souvent une exigence et une importance pour la sécurité, quiconque ajoute sciemment des IFSchars PATHest un terroriste.
ti7
0

Vous devez utiliser plusieurs commandes sur une seule ligne. par exemple:

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

lorsque vous activez votre environnement virtuel sur une seule ligne, je pense qu'il oublie les autres lignes de commande et vous pouvez éviter cela en utilisant plusieurs commandes sur une seule ligne. Cela a fonctionné pour moi :)

Ahmadreza Pourghodrat
la source
0

Quand j'apprenais venv, j'ai créé un script pour me rappeler comment l'activer.

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

Cela présente l'avantage de modifier l'invite.

Alexx Roche
la source