Làm thế nào tôi có thể sử dụng các biến môi trường trong shebang của tôi?


34

Tôi có một kịch bản Python cần được chạy với một cài đặt python cụ thể. Có cách nào để tạo ra một shebang để nó chạy với $FOO/bar/MyCustomPythonkhông?

Câu trả lời:


29

Dòng shebang rất hạn chế. Trong nhiều biến thể unix (bao gồm cả Linux), bạn chỉ có thể có hai từ: một lệnh và một đối số duy nhất. Cũng thường có một giới hạn chiều dài.

Giải pháp chung là viết một trình bao bọc vỏ nhỏ. Đặt tên cho tập lệnh Python foo.pyvà đặt tập lệnh shell bên cạnh foo.pyvà gọi nó foo. Cách tiếp cận này không yêu cầu bất kỳ tiêu đề cụ thể nào trên tập lệnh Python.

#!/bin/sh
exec "$FOO/bar/MyCustomPython" "$0.py" "$@"

Một cách tiếp cận hấp dẫn khác là viết một tập lệnh bao bọc như ở trên và đặt #!/path/to/wrapper/scriptlàm dòng shebang trên tập lệnh Python. Tuy nhiên, hầu hết các đơn vị không hỗ trợ xâu chuỗi các kịch bản shebang, vì vậy điều này sẽ không hoạt động.

Nếu MyCustomPythonlà trong $PATH, bạn có thể sử dụng envđể tìm kiếm nó:

#!/usr/bin/env MyCustomPython
import 

Tuy nhiên, một cách tiếp cận khác là sắp xếp cho tập lệnh vừa là tập lệnh shell hợp lệ (vừa tự tải trình thông dịch Python đúng) và tập lệnh hợp lệ trong ngôn ngữ đích (ở đây là Python). Điều này đòi hỏi bạn phải tìm cách viết một tập lệnh ngôn ngữ kép như vậy cho ngôn ngữ mục tiêu của bạn. Trong Perl, điều này được gọi là if $running_under_some_shell.

#!/bin/sh
eval 'exec "$FOO/bar/MyCustomPerl" -wS $0 ${1+"$@"}'
    if $running_under_some_shell;
use 

Đây là một cách để đạt được hiệu ứng tương tự trong Python. Trong shell, "true"truetiện ích, bỏ qua các đối số của nó (hai chuỗi ký tự đơn :') và trả về một giá trị thực. Trong Python, "true"là một chuỗi đúng khi được hiểu là boolean, vì vậy đây là một iflệnh luôn luôn đúng và thực thi một chuỗi ký tự.

#!/bin/sh
if "true" : '''\'
then
exec "$FOO/bar/MyCustomPython" "$0" "$@"
exit 127
fi
'''
import 

Mã Rosetta có các tập lệnh ngôn ngữ kép như vậy trong một số ngôn ngữ khác.


1
@Chris: mọi thứ đều nằm trong dấu ngoặc đơn. Vui lòng giải thích về
Cẩu

1
Bạn là một phù thủy đẫm máu ... Điều này thật tuyệt. Tôi đã sử dụng điều này để chỉnh sửa PYTHONPATHbiến env để tải các mô-đun từ một vị trí không chuẩn cho tập lệnh CGI trên hệ thống mà tôi không có quyền truy cập root. Cứu người. Cảm ơn một lần nữa.
wspurgin

12

Các dòng Shebang không trải qua quá trình mở rộng biến đổi, vì vậy bạn không thể sử dụng $FOO/MyCustomPythonvì nó sẽ tìm kiếm một tên thực thi có tên là Dollar-FOO -...

Một cách khác là để shebang của bạn trỏ đến tập lệnh shell làm trình thông dịch và tập lệnh shell này sau đó có thể sử dụng các biến môi trường để xác định vị trí chính xác và thực thi nó.

Ví dụ: tạo mypython.shtập lệnh trong /usr/local/bin(hoặc bất kỳ thư mục nào khác trên của bạn $PATH), với nội dung sau:

#! /bin/sh
PYTHON="$FOO/bar/MyCustomPython"
exec "$PYTHON" "$@"

sau đó bạn có thể sử dụng dòng shebang này để thực thi tập lệnh Python thông MyCustomPythonqua mypython.sh:

#!/usr/bin/env mypython.sh

6
Sử dụng $python, không phải $PYTHON- theo quy ước, chúng tôi viết hoa các biến môi trường (PAGER, EDITOR, SHELL ... $PYTHONtrong tập lệnh của bạn không phải là biến môi trường) và các biến shell nội bộ (BASH_VERSION, RANDOM, ...). Tất cả các tên biến khác phải chứa ít nhất một chữ cái viết thường. Quy ước này tránh vô tình ghi đè các biến môi trường và nội bộ. Ngoài ra, không sử dụng tiện ích mở rộng cho tập lệnh của bạn. Các tập lệnh xác định các lệnh mới mà bạn có thể chạy và các lệnh thường không được cung cấp các tiện ích mở rộng.
Chris Xuống

4

Bạn có thể sử dụng đường dẫn tuyệt đối để cài đặt python tùy chỉnh hoặc bạn có thể đặt nó vào $PATHvà sử dụng #!/usr/bin/env [command]. Mặt khác, viết một trình bao bọc cho nó và sử dụng execđể thay thế hình ảnh quá trình, như một ví dụ:

#!/bin/bash
exec "$ENV/python" "$@"

3

Trước tiên, hãy xác định phiên bản Python của bạn khác với Python chuẩn đã được cài đặt như thế nào (ví dụ: một mô-đun bổ sung) và sau đó khi bắt đầu chương trình 'chuyển đổi' cách Python được gọi:

#!/usr/bin/python
import os
import sys
try:
    import MyCustomModule
except ImportError:
    # only need to use expandvar if you know the string below has an envvar
    custprog = os.path.expandvar("$FOO/bar/MyCustomPython")
    os.execv(custprog, sys.argv) # call alternate python with the same arguments
    raise SystemExit('could not call %s' % custprog)
# if we get here, then we have the correct python interpreter

Điều này sẽ cho phép chương trình được gọi bởi bất kỳ phiên bản Python nào khác. Tôi làm một cái gì đó tương tự với một ví dụ với thư viện sql tích hợp không thể được nhập dưới dạng một mô-đun trong python của hệ thống.


0

Nếu bạn có thể thay thế $FOOtrong $FOO/bar/MyCustomPythonvới các tùy chọn con đường bê tông, bạn có thể nói với các envdòng công việc nơi để tìm kiếm phiên bản Python tùy chỉnh của bạn bằng cách trực tiếp thiết lập một tùy chỉnh PATHtrong đó.

#!/usr/bin/env PATH="/path1/to/MyCustomPython:/path2/to/MyCustomPython" python

Chỉnh sửa : Có vẻ như chỉ hoạt động mà không có dấu ngoặc kép xung quanh việc gán giá trị PATH:

#!/usr/bin/env PATH=/path1/to/MyCustomPython:/path2/to/MyCustomPython python

5
Coi chừng việc này không hoạt động trên tất cả các biến thể unix (ví dụ không phải trên Linux). Và bạn đang xóa tất cả các thư mục hiện có khỏi đường dẫn, điều này có khả năng gây ra sự cố.
Gilles 'SO- ngừng trở nên xấu xa'

1
Mở rộng tốt hơn PATHnhư thế này:PATH=$PATH:/path/to/whatever...
Bengt
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.