Jak pozyskać aktywację virtualenv w skrypcie Bash

105

Jak utworzyć skrypt Bash, aby aktywować virtualenv w języku Python?

Mam strukturę katalogów taką jak:

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

Mogę aktywować virtualenv poprzez:

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

Jednak zrobienie tego samego ze skryptu Bash nic nie robi:

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

Co ja robię źle?

Cerin
źródło
6
Kiedy uruchamiasz skrypt powłoki, w rzeczywistości tworzysz nową powłokę. Celem użycia sourcejest zmiana czegoś w bieżącej powłoce. Możesz użyć Pythona virtualenv, używając pełnej ścieżki ./env/bin/python.
Pablo Navarro
@NgureNyaga, Nie, to pytanie nie jest takie samo jak moje. Pytają, jak pozyskać z dowolnej lokalizacji. Już wiem, jak to zrobić. Pytam, jak pozyskiwać źródła w niestandardowym skrypcie bash i utrzymywać źródło.
Cerin

Odpowiedzi:

83

Kiedy pobierasz źródło, ładujesz skrypt aktywacyjny do aktywnej powłoki.

Kiedy robisz to w skrypcie, ładujesz go do tej powłoki, która kończy pracę po zakończeniu skryptu i wracasz do oryginalnej, nieaktywowanej powłoki.

Najlepszym rozwiązaniem byłoby zrobienie tego w funkcji

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

lub alias

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

Mam nadzieję że to pomoże.

richo
źródło
for windows c: \ tutorial>. \ env \ Scripts \
activ
7
Nie miałem absolutnie pojęcia, co się dzieje, kiedy tworzę źródła. To znacznie zmieniło moje skrypty basha na lepsze. Dziękuję Ci!
Robert Townley
1
Twój pomysł na alias też mi się podobał. Tylko uwaga: musiałem to umieścić (alias abcdef = "source ... / bin / activ") w moim skrypcie .zshrc (lub .bashrc dla użytkowników basha), aby działał.
shahins
Jest to dobre rozwiązanie, jeśli masz swoje virtualenvs używające domyślnej nazwy folderu. Kiedyś miałem więcej niż jedno repozytorium w folderze, robiąc bałagan na virtualenvach. Teraz przełączyłem się na to domyślne.
3manuek
3
Jestem całkiem nowy w bashu itp. Czy możesz rozszerzyć ten przykład tak, aby pokazywał pełny skrypt?
AljoSt
60

Powinieneś wywołać skrypt bash używając source.

Oto przykład:

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

Na swojej powłoce po prostu nazwij to tak:

> source venv.sh

Lub jak zasugerował @outmind: (Zauważ, że to nie działa z zsh)

> . venv.sh

Proszę, wskazanie powłoki zostanie umieszczone w twoim znaku zachęty.

Flavio Garcia
źródło
2
lub nawet po prostu „. venv.sh”
przechytrzyć
bez względu na to, co próbuję, source "/home/surest/Desktop/testservers/TEST_VENV/venv3/bin/activate"daje to :/home/surest/Desktop/testservers/TEST_VENV/py3.sh: 10: /home/surest/Desktop/testservers/TEST_VENV/py3.sh: source: not found
Nic też nie dostaję, kiedy piszę which sourcew source venv3/bin/activatezachęcie powłoki, ale robi to, czego się spodziewam i otwieram venv. ...
Dlaczego to działa, ale source ./env/bin/activate(z tym samym #!/bin/bashprefiksem) nie? Jaka jest różnica między używaniem cudzysłowów a nie?
blacksite
Nie mam problemu z używaniem źródła wewnątrz skryptu bez cudzysłowów. Widzę problem, source ./env/bin/activateponieważ jest to zależne od ścieżki, którą biegniesz, prawda? Jeśli zmienisz katalog wewnątrz skryptu, możesz przejść do względnej.
Flavio Garcia
14

Chociaż nie dodaje przedrostka „(.env)” do znaku zachęty powłoki, stwierdziłem, że ten skrypt działa zgodnie z oczekiwaniami.

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

na przykład

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
źródło
5
technicznie tworzysz podpowłokę. Niekoniecznie jest to problem, ale powinieneś to przeliterować w OP.
richo
Zadziałało, ale wcześniej musiałem udzielić pozwolenia na mój plik „aktywuj”.
Adrian Lopez,
1
To działa w 2019 roku! Na MacOS po prostu musiałem zmienić /bin/bashna/usr/bin/env bash
valem
Działa w Ubuntu 18.04 AWS EC2 w 2020 roku. Zastanawiam się, jak dezaktywować używając tej samej logiki?
CSF Junior
Jesteś deactivatez podpowłoki za pomocą exitlub Ctrl + d
Alexx Roche
10

Sourcing uruchamia polecenia powłoki w bieżącej powłoce. Kiedy pozyskujesz źródło wewnątrz skryptu, tak jak robisz powyżej, wpływasz na środowisko tego skryptu, ale kiedy skrypt kończy pracę, zmiany środowiska są cofane, ponieważ faktycznie wyszły poza zakres.

Jeśli zamierzasz uruchamiać polecenia powłoki w virtualenv, możesz to zrobić w swoim skrypcie po pobraniu skryptu aktywacyjnego. Jeśli twoim zamiarem jest interakcja z powłoką wewnątrz virtualenv, możesz stworzyć podpowłokę wewnątrz swojego skryptu, która odziedziczy środowisko.

zigg
źródło
3

Oto skrypt, którego często używam. Uruchom to jako$ source script_name

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

activate
Sandjaie Ravi
źródło
2

Do czego służy pozyskiwanie skryptu bash?

  1. Jeśli zamierzasz przełączać się między wieloma virtualenvami lub szybko wprowadzać jeden virtualenv, czy próbowałeś virtualenvwrapper? Zapewnia dużo utils jak workon venv, mkvirtualenv venvi tak dalej.

  2. Jeśli po prostu uruchamiasz skrypt Pythona w pewnym virtualenv, użyj go, /path/to/venv/bin/python script.pyaby go uruchomić.

iMom0
źródło
Właściwie chciałbym zadzwonić workon ...ze skryptu bash. (Ponieważ chcę wykonać kolejne rzeczy później za każdym razem podczas jego uruchamiania). Nie mogę jednak znaleźć sposobu, aby to zadziałało.
Daniel B.,
1

Możesz to również zrobić za pomocą podpowłoki, aby lepiej ograniczyć użycie - oto praktyczny przykład:

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

Ten styl jest szczególnie pomocny, gdy

  • inna wersja commandAlub commandCistnieje w ramach/opt/bin
  • commandBistnieje w systemie PATHlub jest bardzo powszechne
  • te polecenia zawodzą w virtualenv
  • potrzeba wielu różnych virtualenvów
ti7
źródło
Nie zapomnij o podwójnym cudzysłowie $(...)lub w wynikach będzie brakować spacji i tabulatorów.
Eric
"${VAR}"jest ściśle równoważne z "$VAR"tym, że nie potrzebujesz nawiasów klamrowych wokół zmiennych powłoki, ponieważ podwójne cudzysłowy są w rzeczywistości potężniejsze. Wyjątkiem jest użycie modyfikatorów, takich jak na przykład"${VAR:-default_value}"
Eric
PATH=$PATH:/opt/binwymaga odpowiedniego cytowania do obsługi ścieżek ze spacjami i tabulatorami.
Eric
@Eric Dzięki, chociaż możesz użyć editprzycisku pod postami, aby zasugerować zmiany! Co więcej, niech będzie wiadomo, że chociaż jest to często wymóg i ważny dla bezpieczeństwa, każdy, kto świadomie dodaje IFSznaki, PATHjest terrorystą.
ti7
0

Powinieneś użyć wielu poleceń w jednej linii. na przykład:

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

Kiedy aktywujesz swoje wirtualne środowisko w jednej linii, myślę, że zapomina o innych wierszach poleceń i możesz temu zapobiec, używając wielu poleceń w jednym wierszu. U mnie zadziałało :)

Ahmadreza Pourghodrat
źródło
0

Kiedy uczyłem się venv, stworzyłem skrypt, który przypomina mi, jak go aktywować.

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

Ma to tę zaletę, że zmienia monit.

Alexx Roche
źródło