Как я могу использовать переменные окружения в моем shebang?

34

У меня есть скрипт Python, который должен быть запущен с определенной установкой Python. Есть ли способ создать шебанг, чтобы он работал с ним $FOO/bar/MyCustomPython?

eric.frederich
источник

Ответы:

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). Это требует, чтобы вы нашли способ написать такой двухъязыковой скрипт для вашего целевого языка. В Perl это известно как 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"это строка, которая имеет значение true, когда интерпретируется как логическое значение, так что это ifинструкция, которая всегда верна и выполняет строковый литерал.

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

Код Rosetta имеет такие двухъязыковые скрипты на нескольких других языках.

Жиль "ТАК - прекрати быть злым"
источник
1
@ Крис: все внутри одинарных кавычек. Пожалуйста, объясните ...
Стефан Гименес
1
Ты кровавый волшебник ... Это здорово. Я использовал это, чтобы отредактировать PYTHONPATHпеременную env для загрузки модулей из нестандартного расположения для CGI-скрипта в системе, к которой у меня не было root-доступа. Спасатель жизни. Еще раз спасибо.
wspurgin
12

Строки Shebang не подвергаются расширению переменных, поэтому вы не можете использовать их так, $FOO/MyCustomPythonкак если бы вы искали исполняемый файл с именем dollar-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

Вы можете либо использовать абсолютный путь к пользовательской установке Python, либо вы можете указать его $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, которую нельзя импортировать как модуль в системный python.

Arcege
источник
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...
Bengt