Як я можу використовувати змінні середовища у своєму шебангу?


34

У мене є сценарій Python, який потрібно запустити з певною установкою python. Чи є спосіб виготовити шебанг, щоб він працював $FOO/bar/MyCustomPython?

Відповіді:


29

Лінія шебангу дуже обмежена. У багатьох варіантах unix (включаючи Linux) ви можете мати лише два слова: команду та один аргумент. Також часто існує обмеження довжини.

Загальне рішення - написати невелику оболонку-оболонку. Назвіть сценарій Python foo.pyта поставте скрипт оболонки поруч foo.pyі зателефонуйте foo. Цей підхід не вимагає особливого заголовка сценарію Python.

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

Ще один спокусливий підхід - написати скрипт для обгортки, як описаний вище, і поставити #!/path/to/wrapper/scriptяк сценарій shebang на сценарій Python. Однак більшість юніорів не підтримують ланцюжок сценаріїв shebang, тому це не спрацює.

Якщо ви MyCustomPythonзнаходилися в $PATH, ви можете використовувати його envдля пошуку:

#!/usr/bin/env MyCustomPython
import 

Ще один підхід полягає в тому, щоб зробити скрипт дійсним сценарієм оболонки (який завантажує правильний інтерпретатор Python на себе) і дійсним сценарієм на цільовій мові (тут Python). Це вимагає, щоб ви знайшли спосіб написати такий двомовний скрипт для вашої цільової мови. У Перлі це відомо як if $running_under_some_shell.

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

Ось один із способів досягти такого ж ефекту в Python. У оболонці "true"- це trueутиліта, яка ігнорує її аргументи (дві односимвольні рядки :та ') та повертає справжнє значення. У Python "true"- це рядок, який є істинним, коли його інтерпретують як булевий, так що це ifінструкція, яка завжди відповідає дійсності та виконує літеральний рядок.

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

Код Розетти має такі двомовні скрипти на кількох інших мовах.


1
@Chris: усе знаходиться в одній цитаті. Поясніть, будь ласка,…
Стефан Гіменез

1
Ви кривавий чарівник ... Це чудово. Я використовував це для редагування PYTHONPATHзмінної env для завантаження модулів з нестандартного місця для сценарію CGI в системі, до якої не мав кореневого доступу. Рятувальник життя. Знову дякую.
wspurgin

12

Рядки Shebang не зазнають змінного розширення, тому ви не можете використовувати так, $FOO/MyCustomPythonяк це було б для пошуку виконуваного файлу з назвою долар-FOO -...

Альтернативою є те, щоб ваш shebang вказував на скрипт оболонки як інтерпретатор, і цей скрипт оболонки може потім використовувати змінні середовища для пошуку потрібного та виконувати його.

Приклад: створіть mypython.shсценарій у /usr/local/bin(або будь-який інший каталог у вашому $PATH) із наступним вмістом:

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

то ви можете використовувати цю хатину лінію , щоб мати Python скрипт виконується через з MyCustomPythonдопомогою mypython.sh:

#!/usr/bin/env mypython.sh

6
Використовуйте $python, а не $PYTHON- за умовою, ми використовуємо великі розміри змінних середовища (PAGER, EDITOR, SHELL ... $PYTHONу вашому сценарії не є змінною середовища) та внутрішніми змінними оболонок (BASH_VERSION, RANDOM, ...). Усі інші назви змінних повинні містити принаймні одну малу літеру. Ця конвенція дозволяє уникнути випадкових переваг екологічних та внутрішніх змінних. Крім того, не використовуйте розширення для своїх сценаріїв. Сценарії визначають нові команди, які можна виконати, а команди, як правило, не дають розширень.
Кріс Даун

4

Ви можете використовувати абсолютний шлях до встановлення призначеного для користувача пітона, або ви можете помістити його в $PATHі використанні #!/usr/bin/env [command]. В іншому випадку напишіть обгортку для цього і використовуйте execдля заміни зображення процесу, як приклад:

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

3

Спочатку визначте, чим відрізняється ваша версія Python від стандартного вже встановленого Python (наприклад, додатковий модуль), а потім на початку програми "перемкніть", як називається Python:

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

Це повинно дозволяти викликати програму будь-яким іншим екземпляром Python. Я роблю щось подібне для екземпляра із вбудованою бібліотекою sql, яку неможливо імпортувати як модуль у пітоні системи.


0

Якщо ви можете замінити $FOOв $FOO/bar/MyCustomPythonконкретних варіантів шляху, ви можете сказати envпритон лінію , де шукати свій власний Python версії, безпосередньо встановивши звичай PATHв ньому.

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

Редагувати : Здається, працює лише без лапок навколо призначення значення PATH:

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

5
Слідкуйте за тим, щоб це не працювало на всіх версіях unix (наприклад, не в Linux). І ви видаляєте всі існуючі каталоги зі шляху, що, ймовірно, спричинить проблеми внизу лінії.
Жил 'ТАК - перестань бути злим'

1
Краще розгорніть PATHтак:PATH=$PATH:/path/to/whatever...
Бенгт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.