Я нахожусь в некоторой интересной ситуации, когда у меня есть сценарий Python, который теоретически может запускаться различными пользователями с различными средами (и PATH) и на различных системах Linux. Я хочу, чтобы этот скрипт выполнялся на максимально возможном количестве без искусственных ограничений. Вот некоторые известные настройки:
- Python 2.6 является системной версией Python, поэтому python, python2 и python2.6 все существуют в / usr / bin (и эквивалентны).
- Python 2.6 - это системная версия Python, как и выше, но Python 2.7 устанавливается вместе с ним как python2.7.
- Python 2.4 - это системная версия Python, которую мой скрипт не поддерживает. В / usr / bin у нас есть python, python2 и python2.4, которые эквивалентны, и python2.5, который поддерживает скрипт.
Я хочу запустить один и тот же исполняемый скрипт на всех трех из них. Было бы хорошо, если бы он попытался сначала использовать /usr/bin/python2.7, если он существует, затем вернуться к /usr/bin/python2.6, а затем вернуться к /usr/bin/python2.5, а затем просто ошибка, если ни один из них не присутствовал. Я не слишком одержим этим, используя самую последнюю возможную версию 2.x, однако, если она способна найти одного из правильных переводчиков, если он присутствует.
Моим первым желанием было изменить строку Шебанга с:
#!/usr/bin/python
в
#!/usr/bin/python2.[5-7]
так как это хорошо работает в Bash. Но запуск скрипта дает:
/usr/bin/python2.[5-7]: bad interpreter: No such file or directory
Итак, я попробую следующее, которое также работает в Bash:
#!/bin/bash -c /usr/bin/python2.[5-7]
Но опять же, это не с:
/bin/bash: - : invalid option
Хорошо, очевидно, я мог бы просто написать отдельный скрипт оболочки, который находит правильный интерпретатор и запускает скрипт python, используя любой интерпретатор, который он нашел. Мне просто было бы неудобно распространять два файла, где одного должно хватить, если он работает с самым современным установленным интерпретатором Python 2. Просить людей явно вызывать переводчика (например, $ python2.5 script.py
) не вариант. Полагаться на то, что PATH пользователя настроен определенным образом, также не вариант.
Редактировать:
Проверка версий в скрипте Python не будет работать, так как я использую оператор «с», который существует в Python 2.6 (и может использоваться в 2.5 с from __future__ import with_statement
). Это приводит к немедленному сбою сценария с недружественным для пользователя SyntaxError и лишает меня возможности когда-либо сначала проверить версию и выдать соответствующую ошибку.
Пример: (попробуйте это с интерпретатором Python менее 2.6)
#!/usr/bin/env python
import sys
print "You'll never see this!"
sys.exit()
with open('/dev/null', 'w') as out:
out.write('something')
import sys; sys.version_info()
чтобы проверить, есть ли у пользователя требуемая версия Python../script.py
Е.) Заставит python2.4 выполнить его, что заставит ваш код обнаружить, что это была неправильная версия (и, по-видимому, выход). Но есть совершенно хороший python2.5, который можно было бы использовать вместо интерпретатора!exec
если да, то выведите ошибку.execve
). Аргументы - строковые литералы, без глобализации, без регулярных выражений. Вот и все. Даже если первый аргумент - «/ bin / bash», а второй параметр («-c ...»), эти параметры не анализируются оболочкой. Они передаются необработанным в исполняемый файл bash, поэтому вы получаете эти ошибки. Плюс, шебанг работает, только если он в начале. Боюсь, вам здесь не повезло (если не считать сценария, который находит интерпретатора python и передает его в ЗДЕСЬ документ, который звучит как ужасный беспорядок).Ответы:
Я не эксперт, но я считаю, что вы не должны указывать точную версию Python для использования и оставить этот выбор для системы / пользователя.
Также вы должны использовать это вместо жесткого пути к python в скрипте:
или
Он рекомендуется при помощи Python док во всех версиях:
В разных дистрибутивах Python может быть установлен в разных местах, поэтому
env
будет искать его вPATH
. Он должен быть доступен во всех основных дистрибутивах Linux и из того, что я вижу во FreeBSD.Скрипт должен выполняться с той версией Python, которая находится в вашем PATH и которая выбрана вашим дистрибутивом *.
Если ваш сценарий совместим со всеми версиями Python, кроме 2.4, вам следует просто проверить внутри него, работает ли он в Python 2.4, вывести некоторую информацию и выйти.
Больше читать
env
.сноска
* В Gentoo есть инструмент под названием
eselect
. Используя его, вы можете установить версии по умолчанию для различных приложений (включая Python) по умолчанию:источник
Основываясь на некоторых идеях из нескольких комментариев, мне удалось собрать воедино действительно уродливый хак, который, кажется, работает. Сценарий становится bash-сценарием, оборачивает сценарий Python и передает его интерпретатору Python через «документ здесь».
С начала:
Код Python идет здесь. Тогда в самом конце:
Когда пользователь запускает скрипт, самая последняя версия Python между 2.5 и 2.7 используется для интерпретации остальной части скрипта как документ здесь.
Объяснение некоторых махинаций:
Добавленный мной материал с тройными кавычками также позволяет импортировать этот же скрипт как модуль Python (который я использую для тестирования). При импорте в Python все, что находится между первой и второй тройной одинарной кавычкой, интерпретируется как строка уровня модуля, а третья тройная одинарная кавычка закомментируется. Остальное обычный Python.
При непосредственном запуске (как в bash-скрипте) первые две одинарные кавычки становятся пустой строкой, а третья одинарная кавычка образует другую строку с четвертой одинарной кавычкой, содержащей только двоеточие. Эта строка интерпретируется Bash как no-op. Все остальное - это синтаксис Bash для перемещения двоичных файлов Python в / usr / bin, выбора последнего и запуска exec, передавая оставшуюся часть файла в виде документа здесь. Документ здесь начинается с тройной одинарной кавычки Python, содержащей только знак хеш / фунт / октоторп. Затем остальная часть сценария интерпретируется как нормальная, пока строка, читающая «# EOF», не завершит документ здесь.
Я чувствую, что это извращение, поэтому я надеюсь, что у кого-то есть лучшее решение.
источник
# ft=python
.Строка shebang может указывать только фиксированный путь к интерпретатору. Есть
#!/usr/bin/env
хитрость, чтобы найти переводчика,PATH
но это все. Если вы хотите больше изощренности, вам нужно написать некоторый код оболочки оболочки.Наиболее очевидное решение - написать скрипт-обертку. Вызовите скрипт python
foo.real
и создайте скрипт-оберткуfoo
:Если вы хотите поместить все в один файл, вы часто можете сделать его полиглотом, который начинается со
#!/bin/sh
строки (так будет выполняться оболочкой), но также является допустимым скриптом на другом языке. В зависимости от языка полиглот может быть невозможен (например, если он#!
вызывает синтаксическую ошибку). В Python это не очень сложно.(Весь текст между
'''
и'''
является строкой Python на верхнем уровне, которая не имеет никакого эффекта. Для оболочки вторая строка,''':'
которая после удаления кавычек является командой no-op:
.)источник
# EOF
в конце, как в этом ответе . Ваш подход в основном такой же, как изложенный здесь .Поскольку ваши требования содержат известный список двоичных файлов, вы можете сделать это в Python следующим образом. Это не сработало бы после однозначной минорной / мажорной версии Python, но я не думаю, что это произойдет в ближайшее время.
Запускает самую верхнюю версию, расположенную на диске, из упорядоченного, увеличивающегося списка версионных питонов, если версия, помеченная в двоичном файле, выше, чем текущая версия исполняемого python. «Упорядоченный увеличивающийся список версий» является важным битом для этого кода.
Извиняюсь за мой неуклюжий питон
источник
from __future__ import with_statement
, что должно быть первым в скрипте Python. Я не думаю, что вы знаете, как выполнить это действие при запуске нового переводчика?with
s как обычный импорт? Есть ли дополнительнаяif mypy == 25: from __future__ import with_statement
работа перед «нормальными вещами»? Возможно, вам не нужен if, если вы не поддерживаете 2.4.Вы можете написать небольшой скрипт bash, который проверяет наличие исполняемого файла phython и вызывает его со скриптом в качестве параметра. Затем вы можете сделать этот скрипт целевым объектом линии shebang:
И этот скрипт просто делает (после поиска):
Я не был уверен, примет ли ядро эту косвенность сценария, но я проверил, и это работает.
Редактировать 1
Чтобы сделать эту неловкую невосприимчивость хорошим предложением, наконец:
Можно объединить оба скрипта в одном файле. Вы просто пишете скрипт Python в виде документа здесь в скрипте bash (если вы измените скрипт Python, вам просто нужно снова скопировать скрипты вместе). Либо вы создаете временный файл, например, в / tmp, либо (если Python поддерживает это, я не знаю), вы предоставляете скрипт как ввод для интерпретатора:
источник
$(ls /usr/bin/python?.? | tail -n1 )
но мне не удалось использовать это умно в шебанге.