stringtranslate.com

Шебанг (Unix)

В вычислительной технике шебанг это последовательность символов #!, состоящая из знака числа символов (также известного как диез или хэш ) и восклицательного знака (также известного как бэнг ), в начале скрипта . Его также называют диез-восклицательный знак , ша-бэнг , [1] [2] хэшбэнг , [3] [4] фунт-бэнг , [5] [6] или хэш-плинг . [7]

Когда текстовый файл с shebang используется как исполняемый файл в Unix-подобной операционной системе, механизм загрузчика программ анализирует оставшуюся часть начальной строки файла как директиву интерпретатора . Загрузчик выполняет указанную программу интерпретатора , передавая ей в качестве аргумента путь, который изначально использовался при попытке запустить скрипт, чтобы программа могла использовать файл в качестве входных данных. [8] Например, если скрипт назван с путем path /to/script и начинается со строки #!/bin/sh, то загрузчик программ получает указание запустить программу /bin/sh , передавая path/to/script в качестве первого аргумента.

Интерпретатор обычно игнорирует строку «шебанг», поскольку символ «#» является маркером комментария во многих языках сценариев; некоторые интерпретаторы языков, которые не используют знак «решетка» для начала комментариев, все равно могут игнорировать строку «шебанг», распознавая ее цель. [9]

Синтаксис

Форма директивы интерпретатора Shebang выглядит следующим образом: [8]

#! интерпретатор [ необязательный-аргумент ]

где интерпретатор — это путь к исполняемой программе. Пробел между #! и интерпретатором необязателен. До или после интерпретатора может быть любое количество пробелов или табуляции . Необязательный аргумент будет включать любые дополнительные пробелы до конца строки.

В Linux файл, указанный интерпретатором, может быть выполнен, если он имеет права на выполнение и является одним из следующих:

В Linux и Minix интерпретатор также может быть скриптом. Цепочка shebangs и wrappers дает непосредственно исполняемый файл, который получает обнаруженные скрипты в качестве параметров в обратном порядке. Например, если файл /bin/A является исполняемым файлом в формате ELF , файл /bin/B содержит shebang #!/bin/A optparam, а файл /bin/C содержит shebang #!/bin/B, то исполняемый файл /bin/C разрешается в /bin/B /bin/C, который в конечном итоге разрешается в /bin/A optparam /bin/B /bin/C.

В операционных системах на базе Solaris и Darwin (например, macOS ) файл, указанный интерпретатором, должен быть исполняемым двоичным файлом и сам по себе не может быть скриптом. [10]

Примеры

Некоторые типичные фразы из «шебанга»:

Строки Shebang могут включать определенные параметры, которые передаются интерпретатору. Однако реализации различаются в поведении анализа параметров; для переносимости следует указывать только один параметр без каких-либо встроенных пробелов. [11] Дополнительные рекомендации по переносимости приведены ниже.

Цель

Директивы интерпретатора позволяют использовать скрипты и файлы данных в качестве команд, скрывая детали их реализации от пользователей и других программ, устраняя необходимость указывать префикс интерпретатора перед скриптами в командной строке.

Например, рассмотрим скрипт, имеющий начальную строку #!/bin/sh -x. Его можно вызвать, просто указав путь к файлу, например some/path/to/foo, [12] и некоторые параметры, например barи baz:

некоторый/путь/к/foo бар баз

В этом случае /bin/shвызывается на своем месте с параметрами -x, some/path/to/foo, bar, и baz, как если бы исходная команда была

/bin/sh -x некоторый/путь/к/foo bar baz

Большинство интерпретаторов делают любые дополнительные аргументы доступными для скрипта. Если /bin/shэто POSIX-совместимая оболочка , то barи bazпредставляются скрипту как позиционный массив параметров "$@", а по отдельности как параметры "$1"и "$2"соответственно.

Поскольку начальный символ # используется для введения комментариев в языке оболочки POSIX (и в языках, которые понимают многие другие интерпретаторы), вся строка shebang игнорируется интерпретатором. Однако игнорировать строку shebang может только интерпретатор, и не все так делают; таким образом, скрипт, состоящий из следующих двух строк, просто выводит обе строки при запуске:

#!/bin/котПривет, мир!

Сильные стороны

По сравнению с использованием глобальных списков ассоциаций между расширениями файлов и интерпретирующими приложениями, метод директив интерпретатора позволяет пользователям использовать интерпретаторы, неизвестные на глобальном системном уровне, и без прав администратора. Он также позволяет выбирать конкретный интерпретатор, не перегружая пространство имен расширений файлов (где одно расширение файла относится к нескольким типам файлов), и позволяет изменять язык реализации скрипта, не изменяя синтаксис его вызова другими программами. Вызывающим скрипт не нужно знать, какой язык реализации, поскольку сам скрипт отвечает за указание используемого интерпретатора.

Портативность

Место проведения программы

Shebangs должен указывать абсолютные пути (или пути относительно текущего рабочего каталога) к системным исполняемым файлам; это может вызвать проблемы в системах с нестандартной структурой файловой системы. Даже если системы имеют довольно стандартные пути, вполне возможно, что варианты одной и той же операционной системы будут иметь разные расположения для нужного интерпретатора. Python , например, может находиться в /usr/bin/python3 , /usr/local/bin/python3 или даже в чем-то вроде /home/username/bin/python3 , если установлен обычным пользователем.

Аналогичная проблема существует для оболочки POSIX , поскольку POSIX требует только имени sh , но не требует пути. Распространенным значением является /bin/sh , но некоторые системы, такие как Solaris, имеют POSIX-совместимую оболочку в /usr/xpg4/bin/sh . [13] Во многих системах Linux /bin/sh является жесткой или символической ссылкой на /bin/bash , оболочку Bourne Again (BASH). Использование специфичного для bash синтаксиса при сохранении shebang, указывающего на sh, также непереносимо. [14]

Из-за этого иногда требуется редактировать строку shebang после копирования скрипта с одного компьютера на другой, поскольку путь, который был закодирован в скрипте, может не применяться на новой машине, в зависимости от согласованности в прошлых соглашениях о размещении интерпретатора. По этой причине и потому, что POSIX не стандартизирует имена путей, POSIX не стандартизирует эту функцию. [15] Инструмент GNU Autoconf может проверить поддержку системы с помощью макроса AC_SYS_INTERPRETER. [16]

Часто для обхода этого ограничения можно использовать программу /usr/bin/env , введя уровень косвенности . За ней следует /usr/bin/env , а затем желаемая команда без полного пути, как в этом примере:#!

#!/usr/bin/env ш

В основном это работает, поскольку путь /usr/bin/env обычно используется для утилиты env , и она вызывает первую sh, найденную в $PATH пользователя , обычно /bin/sh .

Этот конкретный пример (с использованием sh ) имеет ограниченную полезность: ни /bin/sh , ни /usr/bin/env не являются универсальными, с похожим количеством устройств, которых не хватает для каждого из них. В более широком смысле использование #!/usr/bin/env для любого скрипта все еще имеет некоторые проблемы с переносимостью с OpenServer 5.0.6 и Unicos 9.0.2, в которых есть только /bin/env и нет /usr/bin/env .

Использование #!/usr/bin/env приводит к косвенному использованию во время выполнения , что может привести к снижению безопасности системы; по этой причине некоторые комментаторы рекомендуют не использовать его [17] в пакетном программном обеспечении, оставляя его только для «образовательных примеров».

Интерпретация характера

Другая проблема переносимости — интерпретация аргументов команды. Некоторые системы, включая Linux, не разделяют аргументы; [18] например, при запуске скрипта с первой строкой,

#!/usr/bin/env python3 -c

весь текст после первого пробела рассматривается как один аргумент, то есть python3 -cбудет передан как один аргумент в /usr/bin/env , а не как два аргумента. Cygwin также ведет себя таким образом.

Сложные вызовы интерпретатора возможны с помощью дополнительной оболочки . FreeBSD 6.0 (2005) ввела опцию -S для своего env , поскольку она изменила поведение чтения shebang на неразделение. Эта опция сообщает env о необходимости разбить саму строку. [19] Утилита GNU env , начиная с coreutils 8.30 (2018), также включает эту функцию. [20] Хотя использование этой опции смягчает проблему переносимости на стороне ядра с разделением, она добавляет требование, чтобы env поддерживал это конкретное расширение.

Другая проблема — скрипты, содержащие символ возврата каретки сразу после строки shebang, возможно, в результате редактирования в системе, использующей разрывы строк DOS , например, Microsoft Windows . Некоторые системы интерпретируют символ возврата каретки как часть команды интерпретатора , что приводит к сообщению об ошибке. [21]

Магическое число

Shebang на самом деле является понятным человеку экземпляром магического числа в исполняемом файле, магическая строка байтов0x23 0x21 , двухсимвольная кодировка в ASCII # ! . Это магическое число обнаруживается семейством функций " exec ", которые определяют, является ли файл скриптом или исполняемым двоичным файлом. Наличие shebang приведет к выполнению указанного исполняемого файла, обычно интерпретатора языка скрипта. Утверждалось [22] , что некоторые старые версии Unix ожидают, что за обычным shebang будут следовать пробел и слэш ( ), но это, по-видимому, неверно; [11] вместо этого традиционно разрешались пробелы после shebang, и иногда они документировались пробелом, как описано в историческом письме 1980 года ниже.#! /

Символы shebang представлены теми же двумя байтами в расширенных кодировках ASCII, включая UTF-8 , которая обычно используется для скриптов и других текстовых файлов в современных Unix-подобных системах. Однако файлы UTF-8 могут начинаться с необязательной метки порядка байтов (BOM); если функция "exec" специально обнаруживает байты 0x23 и 0x21 , то наличие BOM ( 0xEF 0xBB 0xBF ) перед shebang предотвратит выполнение интерпретатора скрипта. Некоторые авторитетные источники рекомендуют не использовать метку порядка байтов в скриптах POSIX (Unix-подобных) [23] по этой причине, а также для более широкой совместимости и философских соображений. Кроме того, метка порядка байтов не нужна в UTF-8, поскольку эта кодировка не имеет проблем с порядком байтов ; она служит только для идентификации кодировки как UTF-8. [23]

Этимология

Исполняемый файл, начинающийся с директивы интерпретатора, просто называется скриптом, часто предваряемым именем или общей классификацией предполагаемого интерпретатора. Название shebang для двух отличительных символов могло произойти от неточного сокращения SHArp bang или haSH bang , ссылаясь на два типичных названия для них в Unix. Другая теория относительно sh в shebang заключается в том, что это от оболочки по умолчанию sh , обычно вызываемой с помощью shebang. [ 24] Такое использование было актуальным к декабрю 1989 года [25] и, вероятно, ранее.

История

Шебанг был представлен Деннисом Ритчи между 7 и 8 изданиями в Bell Laboratories. Он также был добавлен в релизы BSD от Berkeley's Computer Science Research (присутствовал в 2.8BSD [26] и активировался по умолчанию в 4.2BSD). Поскольку AT&T Bell Laboratories Edition 8 Unix и более поздние издания не были выпущены для публики, первое широко известное появление этой функции было в BSD.

Отсутствие директивы интерпретатора, но поддержка сценариев оболочки, очевидны в документации из версии 7 Unix в 1979 году, [27] где вместо этого описывается средство оболочки Bourne, где файлы с разрешением на выполнение будут обрабатываться оболочкой особым образом, которая (иногда в зависимости от начальных символов в сценарии, таких как ":" или "#") порождает подоболочку, которая будет интерпретировать и выполнять команды, содержащиеся в файле. В этой модели сценарии будут вести себя как другие команды, только если будут вызваны из оболочки Bourne. Попытка напрямую выполнить такой файл через собственный системный вызов exec() операционной системы потерпит неудачу, не позволяя сценариям вести себя единообразно как обычные системные команды.

Улучшенные скрипты оболочки версии 8

В более поздних версиях Unix-подобных систем эта непоследовательность была устранена. Деннис Ритчи представил поддержку ядра для директив интерпретатора в январе 1980 года для версии 8 Unix со следующим описанием: [26]

От uucp, четверг, 10 января, 01:37:58, 1980 г.>От dmr Чт Янв 10 04:25:49 1980 удален от исследованийСистема была изменена таким образом, что если файл выполняетсяначинается с магических символов #!, остальная часть строки понятнабыть именем интерпретатора для исполняемого файла.Раньше (и фактически до сих пор) большую часть этой работы выполняла оболочка;он автоматически запустил себя в текстовом файле с исполняемым режимомкогда имя текстового файла было введено как команда.Ввод объекта в систему дает следующеепреимущества.1) Это делает скрипты оболочки более похожими на настоящие исполняемые файлы,потому что они могут быть предметом «исполнения».2) Если вы выполните команду «ps» во время выполнения такой команды, это реальновместо «ш» появляется имя.Аналогично, бухгалтерский учет ведется на основе настоящего имени.3) Скрипты оболочки могут быть set-user-ID . [a]4) Проще иметь в наличии альтернативные оболочки;например, если вам нравится Berkeley CSH, то нет никаких сомненийкакая оболочка должна интерпретировать файл.5) Это позволит другим переводчикам более плавно влиться в коллектив.Чтобы воспользоваться этой замечательной возможностью,помещать #! /bin/ш в левом поле первой строки ваших сценариев оболочки.Пробелы после ! допустимы. Используйте полный путь (поиск не производится).В настоящее время длина всей строки ограничена 16 символами, ноэтот лимит будет повышен.

Неназванная функция скрипта оболочки

Однако создатель функции не дал ей названия: [29]

От:  "Ritchie,  Dennis  M  (Dennis)**  CTR  **"  <dmr@[redacted]> Кому:  <[redacted]@ talisman.org > Дата: Чт, 19 Ноя 2009 18:37:37 -0600 Тема: RE: Как -вы- называете свою #!<что-то> строку ?          Не припомню, чтобы мы когда-либо давали ему нормальное название.Было довольно поздно, когда он вошел, я думаю, что яЭту идею я получил от кого-то на одной из конференций UCB.на Berkeley Unix; я, возможно, был одним из первых, ктона самом деле установить его, но это была идея, которая пришла мне в головуоткуда-то еще.Что касается названия: вероятно, что-то описательное, например"hash-bang" хотя это имеет специфически британский привкус, нов любом случае я не помню, чтобы я использовал какое-то ласковое имядля строительства.

Поддержка ядра для директив интерпретатора распространилась на другие версии Unix, и одну современную реализацию можно увидеть в исходном коде ядра Linux в fs/binfmt_script.c . [30]

Этот механизм позволяет использовать скрипты практически в любом контексте, в котором могут использоваться обычные скомпилированные программы, включая полноценные системные программы и даже интерпретаторы других скриптов. Однако, в качестве предостережения, некоторые ранние версии поддержки ядра ограничивали длину директивы интерпретатора примерно 32 символами (всего 16 в первой реализации), не могли отделить имя интерпретатора от каких-либо параметров в директиве или имели другие странности. Кроме того, некоторые современные системы позволяют ограничить или отключить весь механизм в целях безопасности (например, поддержка set-user-id была отключена для скриптов во многих системах).

Обратите внимание, что даже в системах с полной поддержкой ядра для магического числа #! некоторые скрипты, не имеющие директив интерпретатора (хотя обычно все еще требующие разрешения на выполнение), все еще могут быть запущены благодаря устаревшей обработке скриптов оболочки Bourne, все еще присутствующей во многих ее современных потомках. Затем скрипты интерпретируются оболочкой пользователя по умолчанию.

Смотрите также

Примечания

  1. ^ Функция setuid отключена в большинстве современных операционных систем после того, как стало известно, что состояние гонки может быть использовано для изменения скрипта во время его обработки. [28]

Ссылки

  1. ^ "Advanced Bash Scripting Guide: Chapter 2. Starting Off With a Sha-Bang". Архивировано из оригинала 10 декабря 2019 г. Получено 10 декабря 2019 г.
  2. Купер, Мендель (5 ноября 2010 г.). Advanced Bash Scripting Guide 5.3 Том 1. lulu.com. стр. 5. ISBN 978-1-4357-5218-4.
  3. ^ Макдональд, Мэтью (2011). HTML5: The Missing Manual. Севастополь, Калифорния: O'Reilly Media . стр. 373. ISBN 978-1-4493-0239-9.
  4. ^ Лутц, Марк (сентябрь 2009 г.). Изучаем Python (4-е изд.). O'Reilly Media . стр. 48. ISBN 978-0-596-15806-4.
  5. ^ Гюлих, Гундаварам и Бирзниекс, Скотт, Шишир и Гюнтер (29 июля 2000 г.). Программирование CGI с помощью PERL (2-е изд.). O'Reilly Media . стр. 358. ISBN 978-1-56592-419-2.{{cite book}}: CS1 maint: несколько имен: список авторов ( ссылка )
  6. Ли Хетланд, Магнус (4 октября 2005 г.). Начало Python: от новичка до профессионала. Апресс. п. 21. ISBN 978-1-59059-519-0.
  7. ^ Шитка, Джон (24 декабря 2002 г.). Linux+ Руководство по сертификации Linux. Курс Технологии. стр. 353. ISBN 978-0-619-13004-6.
  8. ^ ab "execve(2) - Linux man page" . Получено 21 октября 2010 г. .
  9. ^ "СРФИ 22".
  10. ^ "Python - Python3 shebang line не работает так, как ожидалось".
  11. ^ ab Maschek, Sven (30 декабря 2010 г.). «Магия #!, подробности о механизме shebang/hash-bang: пробел после #! обязателен?». www.in-ulm.de . Получено 18 января 2024 г.
  12. ^ если это разрешено битами разрешения exec файла
  13. ^ "The Open Group Base Specifications Issue 7". 2008. Получено 5 апреля 2010 .
  14. ^ "pixelbeat.org: Распространенные ошибки в скриптах оболочки". Гораздо лучше тестировать скрипты непосредственно в POSIX-совместимой оболочке, если это возможно. Опции `bash --posix` недостаточно, так как она все еще принимает некоторые `башизмы'
  15. ^ "Глава 2. Язык команд оболочки", The Open Group Base Specifications (IEEE Std 1003.1-2017) (выпуск 7-е изд.), IEEE, 2018 [2008], Если первая строка файла команд оболочки начинается с символов "#!", результаты не определены.
  16. ^ Autoconf, Free Software Foundation, Макрос: AC_SYS_INTERPRETER: Проверьте, поддерживает ли система запуск скриптов со строкой вида «#!/bin/sh», чтобы выбрать интерпретатор, который будет использоваться для скрипта.
  17. ^ "Что с #!/usr/bin/env bash?" . Получено 6 марта 2024 г. .
  18. ^ "/usr/bin/env behavior". Mail-index.netbsd.org. 9 ноября 2008 г. Получено 18 ноября 2010 г.
  19. ^ env(1)  –  Руководство по основным командам FreeBSD
  20. ^ "env invocation". GNU Coreutils . Получено 11 февраля 2020 г.
  21. ^ «Возврат каретки приводит к сбою bash». 8 ноября 2013 г.
  22. ^ "GNU Autoconf Manual v2.57, Глава 10: Portable Shell Programming". Архивировано из оригинала 18 января 2008 года . Получено 14 мая 2020 года .
  23. ^ ab "FAQ UTF-8, UTF-16, UTF-32 и BOM: может ли поток данных UTF-8 содержать символ BOM (в форме UTF-8)? Если да, то могу ли я по-прежнему предполагать, что оставшиеся байты UTF-8 находятся в порядке от старшего к младшему?". Unicode . Получено 10 ноября 2023 г. .
  24. ^ "Запись файла жаргона для shebang". Catb.org . Получено 16 июня 2010 г.
  25. ^ Уолл, Ларри . «Perl не понимал скрипты setuid, в которых в первой строке между shebang и именем интерпретатора был пробел». USENET .
  26. ^ ab "Архивные компакт-диски CSRG".
  27. ^ СИСТЕМА РАЗДЕЛЕНИЯ ВРЕМЕНИ UNIX: РУКОВОДСТВО ПРОГРАММИСТА UNIX (PDF) , т. 2A (Седьмое издание), январь 1979 г.
  28. ^ Жиль. "linux - Почему SUID отключен для сценариев оболочки, но не для двоичных файлов?". Information Security Stack Exchange .
  29. ^ Ричи, Деннис. «Деннис Ричи и Hash-Bang». Talisman.org . Получено 3 декабря 2020 г.
  30. ^ Рубини, Алессандро (31 декабря 1997 г.). «Игра с двоичными форматами». Linux Journal . Получено 1 января 2015 г.

Внешние ссылки