Часто в Python-коде вы можете встретить загадочную строку, которая всегда появляется вверху файла и начинается с характерной shebang-последовательности (#!). Это выглядит как не очень полезный комментарий, но в остальном он не похож ни на что другое из мира Python, и заставляет задуматься, что это такое и почему оно здесь. Также сбивает с толку тот факт, что shebang-строка появляется только в некоторых модулях Python.
В этом уроке вы:
- Узнаете, что такое шебанг.
- Узнаете, когда включать шебанг в скрипты Python.
- Определите shebang портативным способом в разных системах.
- Научитесь передавать аргументы команде, определенной в shebang.
- Узнаете ограничения shebang и некоторые из его альтернатив.
- Выполните скрипты через собственный интерпретатор, написанный на Python.
Чтобы продолжить, вы должны иметь базовые знания о командной строке и знать, как запускать из нее скрипты Python. Вы также можете загрузить вспомогательные материалы для этого руководства, чтобы следовать им вместе с примерами кода:
Пример кода: кликните здесь, чтобы загрузить образец кода, который вы будете использовать для выполнения скриптов Python с помощью shebang.
Что такое shebang и когда его следует использовать?
Если коротко, то шебанг — это комментарий особого типа, который вы можете включить в свой исходный код, чтобы указать оболочке операционной системы, где найти интерпретатор для остальной части файла:
Если вы используете шебанг, он должен появиться в первой строке вашего скрипта и должен начинаться со знака решетки ( #), за которым следует восклицательный знак (!), в просторечии известный как «челка», отсюда и название шебанг. Выбор знака решетки для начала этой специальной последовательности символов не случаен, поскольку многие скриптовые языки используют его для встроенных комментариев.
Вы должны убедиться, что вы не ставите никаких других комментариев перед строкой shebang, если вы хотите, чтобы она работала правильно, иначе она не будет распознана! После восклицательного знака укажите абсолютный путь к соответствующему интерпретатору кода, например, Python. Предоставление относительного пути, к сожалению, не будет иметь никакого эффекта.
Вы можете заставить shebang работать в Windows, установив подсистему Windows для Linux (WSL), которая поставляется с оболочкой Unix. В качестве альтернативы Windows позволяет вам создать глобальную ассоциацию файлов между расширением файла, например, .py
и программой, такой как интерпретатор Python, для достижения аналогичного эффекта.
Нередко шебанг сочетается с идиомой name-main, что предотвращает запуск основного блока кода, когда кто-то импортирует файл из другого модуля:
С этим условным оператором Python будет вызывать функцию print()
только тогда, когда вы запускаете этот модуль непосредственно как скрипт — например, указав его путь к интерпретатору Python:
Пока содержимое скрипта начинается с правильно определенной строки shebang, а пользователь вашей системы имеет разрешение на выполнение соответствующего файла, вы можете опустить команду python3
для запуска этого скрипта:
Shebang имеет отношение только к исполняемым скриптам, которые выполняются без явного указания программы для их запуска. Обычно вы не помещаете shebang в модуль Python, который содержит только определения функций и классов, предназначенные для импорта из других модулей. Поэтому используйте shebang, если вы не хотите ставить перед командой, которая запускает ваш скрипт Python, префикс или .python python3
Раньше выделенная строка была необходима, чтобы сообщить интерпретатору, какую кодировку символов он должен использовать для правильного чтения исходного кода, поскольку Python по умолчанию использует ASCII. Однако это было важно только тогда, когда вы напрямую встраивали нелатинские символы, такие как ü или ß, в свой код.
Этот специальный комментарий сегодня не актуален, потому что современные версии Python используют универсальную кодировку UTF-8, которая легко обрабатывает такие символы. Тем не менее всегда предпочтительнее заменять сложные символы их закодированными представлениями с использованием литералов Unicode:
Ваши иностранные коллеги, у которых другая раскладка клавиатуры, будут вам за это благодарны!
Теперь, когда у вас есть общее представление о том, что такое шебанг и когда его использовать, вы готовы изучить его более подробно. В следующем разделе вы более детально рассмотрите, как это работает.
Как работает шебанг?
Обычно для запуска программы в терминале необходимо указать полный путь к конкретному исполняемому бинарному файлу или имя команды, присутствующей в одном из каталогов, перечисленных в переменной среды PATH. Один или несколько аргументов командной строки могут следовать этому пути или команде:
Здесь вы запускаете интерпретатор Python в неинтерактивном режиме против однострочной программы, переданной через параметр -c
. В первом случае вы указываете абсолютный путь к python3
, а во втором случае вы полагаетесь на тот факт, что родительская папка /usr/bin/
включена в путь поиска по умолчанию. Ваша оболочка может найти исполняемый файл Python, даже если вы не укажете полный путь, просматривая каталоги переменной PATH
.
PATH
, ваша оболочка выполнит первую, которую сможет найти. Поэтому результат выполнения команды без явного указания соответствующего пути иногда может быть неожиданным. Это будет зависеть от порядка каталогов в вашей PATH-переменной. Однако позже вы узнаете, как это может быть полезно.На практике большинство ваших программ на Python будут состоять из более чем одной строки кода, распределенного по нескольким модулям. Обычно в вашей программе есть единственная работоспособная точка входа: скрипт, который вы можете передать интерпретатору Python для выполнения:
Пока в этом вызове нет ничего удивительного, потому что вы видели его раньше. Однако обратите внимание, что вы по-прежнему запускаете двоичный исполняемый файл, содержащий машинный код для вашей платформы и компьютерной архитектуры, который, в свою очередь, интерпретирует код Python:
Во многих дистрибутивах Linux python3 – это псевдоним исполняемого файла, который был скомпилирован в Executable and Linkable Format (ELF), который вы можете просмотреть с помощью команды hexdump
.
Однако ваша оболочка также может выполнять скрипты или текстовые файлы, содержащие исходный код, выраженный на интерпретируемом языке высокого уровня, таком как Python, Perl или JavaScript. Поскольку выполнение скриптов потенциально может иметь побочные негативные последствия, особенно если они исходят из ненадежных источников, файлы по умолчанию не являются исполняемыми. Когда вы попытаетесь запустить скрипт Python, не сделав его сначала исполняемым, вы увидите это сообщение об ошибке в терминале:
Как правило, вы можете дать разрешение на выполнение указанного файла его владельцу, пользователю, принадлежащему к группе пользователей, связанной с файлом, или всем остальным. Чтобы позволить любому выполнить ваш скрипт, вы можете изменить его биты режима файла с помощью команды chmod
:
Права доступа к файлам Unix следуют символической нотации, где буква x обозначает разрешение на выполнение, а знак плюс +
– соответствующий бит. На некоторых терминалах это также изменит цвет, используемый для отображения ваших исполняемых скриптов, чтобы вы могли различать их с первого взгляда.
Хотя сейчас вы сможете запустить свой скрипт, он все равно не будет работать так, как вы планировали:
Если вы не включите шебанг в начале файла, оболочка будет считать, что ваш скрипт написан на соответствующем языке оболочки. Например, если вы используете оболочку Bash, то оболочка будет ожидать, что в вашем файле будут найдены команды Bash. Итак, когда он натыкается на вызов функции Python print()
в вашем скрипте, он его не понимает. Обратите внимание, что расширение файла, например .py
, совершенно не имеет значения!
Только когда вы указываете абсолютный путь к вашему интерпретатору Python, используя шебанг в своем скрипте, оболочка будет знать, куда передать этот скрипт:
Это очень удобно, потому что теперь вы можете создавать исполняемые скрипты Python. К сожалению, жестко закодированный абсолютный путь в shebang не является супер переносимым между системами, даже в рамках семейства Unix. Что, если Python был установлен в другом месте или команда python3
была заменена на python
? Как насчет использования виртуальной среды или pyenv? В настоящее время вы всегда будете запускать свой скрипт через интерпретатор Python по умолчанию в операционной системе.
В следующем разделе вы рассмотрите решение этих проблем, улучшив свой шебанг и изучив некоторые альтернативы.
Как вы можете определить портативный shebang?
Наличие фиксированного абсолютного пути в шебанге означает, что ваш скрипт может работать не на всех системах, потому что могут быть небольшие различия.
Помните, что вы не можете указать относительный путь в шебанге, так как он всегда должен быть абсолютным. Из-за этого ограничения многие разработчики следуют обходному пути, используя команду /usr/bin/env
, которая может определить фактический путь к интерпретатору Python:
При вызове без каких-либо аргументов /usr/bin/env
отобразит переменные среды, определенные в вашей оболочке. Его основная цель, однако, состоит в том, чтобы запустить программу в измененной среде, позволяя вам временно переопределить определенные переменные. Например, вы можете изменить язык данной программы, установив LANG-переменную:
Команда git status обычно отображает это сообщение на вашем языке по умолчанию, но здесь вы запрашиваете испанский язык. Обратите внимание, что не каждая программа поддерживает несколько языков, и вам может потребоваться сначала установить дополнительный языковой пакет в вашей операционной системе, чтобы он вступил в силу.
Приятно, что благодаря /usr/bin/env
вам не нужно изменять какие-либо переменные среды для запуска команды:
В качестве побочного эффекта он найдет первое вхождение указанного исполняемого файла, например, python3
, в PATH-переменной и запустит его для вас. Это очень полезно, если учесть, что активация виртуальной среды Python изменяет переменную PATH
в вашем текущем сеансе терминала, добавляя родительскую папку исполняемого файла Python в активную виртуальную среду:
Если в вашей оболочке нет активной виртуальной среды, python3
является сокращением от /usr/bin/python3
. Но как только вы создаете и активируете новую виртуальную среду, та же команда будет указывать на исполняемый файл Python в локальной venv/папке. Вы можете понять, почему это происходит, проверив PATH-переменную, которая теперь начинается с этой папки и имеет приоритет над глобально установленным интерпретатором Python.
Одним из недостатков /usr/bin/env
является то, что он не позволяет вам передавать какие-либо аргументы базовой команде из коробки. Поэтому, если вы выполните команду python3 -i
, чтобы интерпретатор Python продолжал работать в интерактивном режиме после завершения работы вашего скрипта, это создаст проблемы:
К счастью, для этого есть быстрое решение, на которое намекает сообщение об ошибке. Вы можете использовать параметр -S
команды /usr/bin/env
, чтобы разделить следующую строку на отдельные аргументы, передаваемые интерпретатору:
После запуска скрипта вы попадете в интерактивный Python REPL, для проверки состояния переменных, что может быть полезно при постоперационной отладке.
В конце концов, shebang — это относительно простой способ создания исполняемых скриптов Python, но он требует определенного уровня знаний об оболочке, переменных среды и операционной системе, с которой вы работаете. Кроме того, он не идеален с точки зрения переносимости, поскольку в основном работает на Unix-подобных системах.
Если вы не хотите настраивать шебанг самостоятельно, вы можете воспользоваться такими инструментами, как setuptools или Poetry, которые сделают эту работу за вас. Они позволяют настроить удобные точки входа в ваш проект через обычные функции. В качестве альтернативы вы можете создать специальный файл __main__.py, чтобы превратить ваш модуль Python в исполняемый модуль, или вы можете создать исполняемое ZIP-приложение на Python, избегая необходимости использования shebang.
Это достойные альтернативы шебангу, и они позволяют избежать некоторых его недостатков.
Варианты шебанга
До сих пор вы использовали шебанг, чтобы указать конкретную версию интерпретатора Python для ваших скриптов. Однако в некоторых случаях может существовать более одного интерпретатора, способного понимать один и тот же код и работать с ним. Например, вы можете написать скрипт, совместимый с Python 2 и Python 3 одновременно:
Круглые скобки вокруг оператора print в Python 2 в конечном итоге игнорируются, поэтому вы можете безопасно использовать команду python без указания явной версии в своем шебанге, если вы придерживаетесь консервативного синтаксиса:
Черт возьми, вы даже можете запустить этот код через интерпретатор Perl, который также имеет функцию print()
, которая ведет себя аналогично своему аналогу из Python:
Вам даже не нужно менять расширение файла, на что оболочке все равно. Просто обновив строку shebang, вы сможете запустить этот скрипт с Perl, если вы ранее установили его интерпретатор:
Результат выполнения этого скрипта выглядит почти таким же, за исключением того, что Python добавляет завершающую новую строку, а Perl — нет. Это простейший пример программы-полиглота, написанной таким образом, что несколько языков программирования могут ее понимать и выдавать одинаковый результат.
Правильная версия программы Hello, World!, написанной на Perl, может выглядеть примерно так:
Использование круглых скобок вокруг аргументов функции в Perl считается хорошей практикой, но не является строго обязательным. Обратите внимание на символ новой строки \n
в строковом литерале и точку с запятой ;
в конце строки, которая завершает оператор.
Если на вашем компьютере есть Node.js, вы можете запустить JavaScript прямо из своего терминала. Вот аналогичный скрипт Hello, World!, написанный на языке, который раньше был доменом веб-браузеров:
Несмотря на то что знак решетки не является допустимым синтаксисом в JavaScript, сервер Node.js распознает характерную последовательность shebang и игнорирует всю строку перед выполнением остальной части файла.
Приложив немного усилий, вы даже сможете писать скрипты на языке Java, который технически не является языком скриптов. Java требует компиляции своего высокоуровневого кода в байт-код для виртуальной машины Java (JVM), которая чем-то похожа на интерпретатор Python, но для двоичных кодов операций.
Чтобы сделать шебанг возможным с программами Java, вы должны выполнить следующие шаги:
- Убедитесь, что файл с вашим исходным кодом Java не имеет традиционного расширения
.java
. Вы можете задать файлу нейтральное расширение.j
. Как объясняется в этом ответе StackOverflow, это гарантирует, что Java игнорирует недопустимый символ хеш-знака. - Запустите исходный файл с помощью команды
java
вместоjavac
. - Явно установите версию Java 11 с помощью переключателя
–source
.
Вот полный пример такого «скрипта» на Java:
Запуск этого скрипта занимает заметно больше времени, чем аналогичные программы Hello, World!, написанные на настоящих скриптовых языках. Это связано с дополнительным этапом компиляции, который выполняется непосредственно при каждом вызове.
Пока вы можете направить свою оболочку на правильный интерпретатор, вы сможете создавать исполняемые скриптом для любого скриптового языка, включая ваш собственный предметно-ориентированный язык (DSL).
В следующем разделе вы увидите пример базового интерпретатора, написанного на Python, который может выполнять код на загадочном языке программирования, который был выбран из-за его простоты. Шебанг станет связующим звеном между вашим интерпретатором и скриптами DSL.
Как вы можете использовать shebang с пользовательским интерпретатором в Python?
Технические детали создания интерпретатора знаменитого загадочного языка выходят далеко за рамки этого руководства. Вместо этого вы можете найти полный исходный код Python указанного интерпретатора во вспомогательных материалах, поэтому загрузите их прямо сейчас, если вы хотите в интерактивном режиме следить за будущими примерами:
Бесплатный пример кода: щелкните здесь, чтобы загрузить бесплатный образец кода, который вы будете использовать для выполнения скриптов Python с помощью shebang.
После того как вы загрузили интерпретатор, вы можете установить его с помощью pip в новую виртуальную среду:
Это должно добавить пользовательскую команду brainf
в вашу виртуальную среду, что означает, что у вас появится точка входа в установленный пакет Python.
Вы можете запустить эту команду без каких-либо аргументов, и в этом случае она будет ожидать, что вы предоставите код, написанный на вашем предметно-ориентированном языке, через стандартный ввод (stdin), почти как Python REPL. Когда вы закончите вводить свой код, вы должны подтвердить его, нажав на Enter, а затем завершить программу, нажав Ctrl+D
, чтобы отправить символ end-of-file (EOF):
Этот пример кода приводит к печати на экране буквы ASCII A, за которой следует символ новой строки. Добавление одной дополнительной инструкции plus (+
) непосредственно перед первой точкой .
в приведенном выше коде приведет к печати буквы B
. Вы можете немного поэкспериментировать с этим кодом, чтобы почувствовать язык.
Кроме того, вы можете сохранить исходный код в текстовом файле и указать его путь в качестве аргумента команды brainf
:
На этом этапе команда brainf
ведет себя почти как интерпретатор Python. Из-за этого также можно вставить соответствующий шебанг в начало вашего скрипта и сделать его исполняемым:
Ух ты! Помните, что это ваш пользовательский интерпретатор, который был реализован на чистом Python, который запускает этот код и превращает загадочные символы в осмысленные действия.
Если это не было достаточно захватывающим, то не стесняйтесь исследовать некоторые из более продвинутых примеров скриптов, сделанных Дэниелом Б. Кристофани, который поддерживает впечатляющий онлайн-архив своих загадочных скриптов. Взгляните, например, на эту умопомрачительную программу, которая рисует треугольник Серпинского, используя всего семь различных инструкций:
Также есть несколько интерактивных скриптов, которые могут кодировать вводимый текст с помощью шифра ROT-13 или вычислять факториал последовательности Фибоначчи. Возможно, самый впечатляющий пример, который вы когда-либо найдете, — это анимированное решение головоломки «Ханойская башня», созданное Клиффордом Вольфом.
Неудивительно, что его исходный код немного длиннее, чем у других примеров, и весит почти 55 килобайт. Он также работает очень медленно, поэтому видео выше ускорено в пятнадцать раз и показывает только первые несколько шагов алгоритма.
Несмотря на то что они являются игрушечными примерами, они прекрасно демонстрируют возможности использования shebang при выполнении любого языка скриптов. Возможно, они вдохновят вас на разработку собственного предметно-ориентированного языка и его интерпретатора, чтобы вы могли решать более серьезные проблемы.
Лучшие практики для Shebang
Подводя итог, вот несколько правил, которым вы должны следовать, чтобы успешно использовать шебанг в своих скриптах Python:
- Помните, что шебанг применим только к исполняемым скриптам в Unix-подобных операционных системах.
- Если вы не укажете шебанг, ваша оболочка попытается интерпретировать скрипт так, как если бы он был написан на соответствующем языке оболочки.
- Не размещайте шебанг в простых модулях Python, которые предназначены только для импорта, но не для выполнения.
- Убедитесь, что ваш скрипт сохранен в исполняемый файл.
- Рассмотрите возможность сочетания шебанга с правилом name-main (
if __name__ == "__main__":
). - Начните свой скрипт со строки shebang и не размещайте перед ней никаких других комментариев.
- Начните шебанг с последовательности символов #!, чтобы отличить его от стандартного комментария.
- Используйте эту команду /
usr/bin/env python3
, чтобы избежать жесткого указания абсолютного пути к какому-либо конкретному интерпретатору Python. - Избегайте использования команды python, если только ваш скрипт не намеренно обратно совместим с Python 2. Как правило, вам следует использовать более явную команду python3.
- Добавьте флаг
-S
, если вам нужно передать интерпретатору дополнительные аргументы, например,#!/usr/bin/env -S python3 -i
. - Будьте осторожны с количеством символов, которые вы вставляете в свою строку shebang.
Наконец, спросите себя, нужно ли вам добавлять шебанг вручную или его можно сгенерировать автоматически или заменить какой-либо абстракцией более высокого уровня с помощью утилиты в вашей цепочке инструментов.
Заключение
Вы знаете, что такое шебанг, как он работает и когда вы можете захотеть включить его в свои скрипты Python. Вы видели, как определить переносимый шебанг и передать ему аргументы. Вы также рассмотрели несколько примеров shebang и узнали, как использовать shebang с пользовательским интерпретатором, написанным на Python. Наконец, вы рассмотрели некоторые из лучших практик использования shebang в своих скриптах и узнали о его недостатках и альтернативах.
В этом уроке вы:
- Узнали когда включать шебанг в скрипты Python.
- Определили shebang портативным способом в разных системах.
- Передали аргументы команде, определенной в шебанге.
- Узнали ограничения shebang и некоторые из его альтернатив.
- Выполнили скрипты через собственный интерпретатор, написанный на Python.
Теперь, когда вы понимаете, как использовать шебанг, почему бы не попробовать его в своих скриптах? Какие еще варианты использования шебанга вы можете придумать? Дайте знать своим коллегам-программистам в комментариях ниже!
Комментарии