Cách tạo nguồn kích hoạt virtualenv trong tập lệnh Bash


98

Làm thế nào để bạn tạo một tập lệnh Bash để kích hoạt một Python virtualenv?

Tôi có cấu trúc thư mục như:

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

Tôi có thể kích hoạt virtualenv của mình bằng cách:

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

Tuy nhiên, làm điều tương tự từ tập lệnh Bash không có gì:

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

Tôi đang làm gì sai?


6
Khi bạn chạy một tập lệnh shell, bạn thực sự đang tạo một shell mới. Mục đích của việc sử dụng sourcelà thay đổi thứ gì đó trong shell hiện tại. Bạn có thể sử dụng python của virtualenv bằng cách sử dụng đường dẫn đầy đủ ./env/bin/python.
Pablo Navarro

@NgureNyaga, Không, câu hỏi đó không giống với câu hỏi của tôi. Họ đang hỏi cách lấy nguồn từ một vị trí tùy ý. Tôi đã biết cách làm điều này. Tôi đang hỏi cách tạo nguồn trong tập lệnh bash tùy chỉnh và duy trì nguồn.
Cerin

Câu trả lời:


79

Khi bạn nguồn, bạn đang tải tập lệnh kích hoạt vào trình bao hoạt động của mình.

Khi bạn thực hiện điều đó trong một tập lệnh, bạn tải nó vào trình bao đó sẽ thoát ra khi tập lệnh của bạn kết thúc và bạn quay lại trình bao ban đầu, chưa được kích hoạt.

Lựa chọn tốt nhất của bạn là làm nó trong một chức năng

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

hoặc một bí danh

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

Hi vọng điêu nay co ich.


cho windows c: \ tutorial>. \ env \ Scripts \ active
max4ever

6
Tôi hoàn toàn không biết đó là những gì đang xảy ra khi tôi làm nguồn Điều này đã thay đổi rất nhiều kịch bản bash của tôi để tốt hơn. Cảm ơn bạn!
Robert Townley

1
Ý tưởng bí danh của bạn cũng rất hiệu quả đối với tôi. Chỉ cần lưu ý: Tôi phải đặt nó (bí danh abcdef = "source ... / bin / active") trong tập lệnh .zshrc của mình (hoặc .bashrc cho người dùng bash) để nó hoạt động.
shahins

Đây là một giải pháp tốt nếu bạn có các Virtualenv của mình bằng cách sử dụng tên thư mục mặc định. Tôi đã từng có nhiều repo trong thư mục, làm cho các virtualenv trở nên lộn xộn. Tôi đã chuyển sang mặc định này ngay bây giờ.
3manuek

3
Tôi còn khá mới đối với bash, v.v. Bạn có thể mở rộng ví dụ này để nó hiển thị toàn bộ tập lệnh không?
AljoSt

57

Bạn nên gọi tập lệnh bash bằng cách sử dụng nguồn.

Đây là một ví dụ:

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

Trên shell của bạn chỉ cần gọi nó như vậy:

> source venv.sh

Hoặc như @outmind đã đề xuất: (Lưu ý rằng điều này không hoạt động với zsh)

> . venv.sh

Vậy là xong, chỉ báo shell sẽ được đặt trên lời nhắc của bạn.


2
hoặc thậm chí chỉ ". venv.sh"
outmind

bất kể tôi cố gắng gì, điều này source "/home/surest/Desktop/testservers/TEST_VENV/venv3/bin/activate"tạo ra:/home/surest/Desktop/testservers/TEST_VENV/py3.sh: 10: /home/surest/Desktop/testservers/TEST_VENV/py3.sh: source: not found

Tôi cũng không nhận được gì khi gõ which sourcevào dấu nhắc trình bao, nhưng source venv3/bin/activatetôi vẫn thực hiện những gì tôi mong đợi và mở venv. ...

Tại sao điều này hoạt động, nhưng source ./env/bin/activate(với cùng một #!/bin/bashtiền tố) thì không? Sự khác biệt giữa việc sử dụng dấu ngoặc kép và không?
blacksite

Tôi không gặp vấn đề gì khi sử dụng nguồn bên trong tập lệnh mà không có dấu ngoặc kép. Tôi thấy một vấn đề với source ./env/bin/activatevì điều này là liên quan đến đường dẫn bạn đang chạy phải không? Nếu bạn thay đổi thư mục bên trong tập lệnh hơn bạn có thể đi tương đối.
Flavio Garcia

13

Mặc dù nó không thêm tiền tố "(.env)" vào dấu nhắc trình bao, tôi thấy tập lệnh này hoạt động như mong đợi.

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

ví dụ

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

5
về mặt kỹ thuật, bạn đang tạo ra một vỏ con. Nó không nhất thiết là một vấn đề, nhưng bạn nên đánh vần điều đó cho OP.
richo

Nó hoạt động, nhưng tôi phải cấp quyền cho tệp "kích hoạt" của mình trước đó.
Adrian Lopez

1
Điều này hoạt động vào năm 2019! Trên macos Tôi chỉ phải thay đổi /bin/bashđể/usr/bin/env bash
valem

Hoạt động trong Ubuntu 18.04 AWS EC2 vào năm 2020. Tôi tự hỏi làm cách nào để hủy kích hoạt bằng cách sử dụng cùng một logic?
CSF Junior

Bạn deactivatetừ vỏ con bằng exithoặc Ctrl + d
Alexx Roche

10

Tìm nguồn cung cấp chạy các lệnh shell trong shell hiện tại của bạn. Khi bạn tạo nguồn bên trong một tập lệnh như bạn đang làm ở trên, bạn đang ảnh hưởng đến môi trường cho tập lệnh đó, nhưng khi tập lệnh thoát ra, các thay đổi về môi trường sẽ được hoàn tác vì chúng đã vượt ra khỏi phạm vi một cách hiệu quả.

Nếu mục đích của bạn là chạy các lệnh shell trong virtualenv, bạn có thể thực hiện điều đó trong script của mình sau khi tìm nguồn kích hoạt script. Nếu mục đích của bạn là tương tác với một shell bên trong virtualenv, thì bạn có thể tạo ra một sub-shell bên trong script của bạn, nó sẽ kế thừa môi trường.


2

Đây là script mà tôi thường sử dụng. Chạy nó như$ source script_name

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

activate

1

Tìm nguồn cung ứng tập lệnh bash để làm gì?

  1. Nếu bạn có ý định chuyển đổi giữa nhiều virtualenv hoặc nhập một virtualenv nhanh chóng, bạn đã thử virtualenvwrapperchưa? Nó cung cấp rất nhiều utils như thế workon venv, mkvirtualenv venvv.v.

  2. Nếu bạn chỉ chạy một tập lệnh python trong một số virtualenv nhất định, hãy sử dụng /path/to/venv/bin/python script.pyđể chạy nó.


Trên thực tế, tôi muốn gọi workon ...từ một tập lệnh bash. (Bởi vì tôi muốn thực thi những thứ khác sau mỗi lần khởi động nó.) Tuy nhiên, không thể tìm ra cách làm cho nó hoạt động.
Daniel B.

1

Bạn cũng có thể làm điều này bằng cách sử dụng một vỏ con để chứa cách sử dụng của bạn tốt hơn - đây là một ví dụ thực tế:

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

Phong cách này đặc biệt hữu ích khi

  • một phiên bản khác của commandAhoặc commandCtồn tại dưới/opt/bin
  • commandBtồn tại trong hệ thống PATHhoặc rất phổ biến
  • các lệnh này không thành công trong virtualenv
  • một người cần nhiều loại Virtualenv khác nhau

Đừng quên trích dẫn gấp đôi $(...)nếu không bạn sẽ thiếu dấu cách và tab có trong đầu ra.
Eric

"${VAR}"hoàn toàn tương đương với việc "$VAR"bạn không cần dấu ngoặc nhọn xung quanh các biến shell vì dấu ngoặc kép thực sự mạnh hơn. Ngoại lệ là khi sử dụng các công cụ sửa đổi chẳng hạn"${VAR:-default_value}"
Eric

PATH=$PATH:/opt/bincần trích dẫn thích hợp để xử lý các đường dẫn có dấu cách và tab.
Eric

@Eric Cảm ơn bạn, mặc dù bạn có thể sử dụng editnút bên dưới bài đăng để đề xuất các thay đổi cho chúng! Hơn nữa, hãy biết rằng mặc dù nó thường là một yêu cầu và quan trọng đối với sự an toàn, nhưng bất kỳ ai cố tình thêm IFSký tự vào PATHđều là một kẻ khủng bố.
ti7

0

Bạn nên sử dụng nhiều lệnh trong một dòng. ví dụ:

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

Khi bạn kích hoạt môi trường ảo của mình trong một dòng, tôi nghĩ rằng nó sẽ quên các dòng lệnh khác và bạn có thể ngăn điều này bằng cách sử dụng nhiều lệnh trong một dòng. Nó làm việc cho tôi :)


0

Khi tôi học venv, tôi đã tạo một tập lệnh để nhắc nhở tôi cách kích hoạt nó.

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

Điều này có lợi thế là nó thay đổi lời nhắc.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.