Топ питань
Часова шкала
Чат
Перспективи
Шебанг (Unix)
З Вікіпедії, вільної енциклопедії
Remove ads
Шебанг (англ. shebang, також відомий як sha-bang[1][2], hashbang,[3][4] pound-bang[5][6] або hash-pling[7]) — в комп'ютингу це послідовність із двох символів: знаку решітки (також знаного як шарп) та знаку оклику (#!), розміщена на самому початку файлу скрипту.

Коли текстовий файл, що містить шебанг, використовується як виконувана програма в Unix-подібних операційних системах, механізм завантажувача програм розпізнає решту початкового рядка файлу як директиву інтерпретатора. Завантажувач запускає зазначену програму-інтерпретатор, передаючи їй як аргумент шлях, який був використаний при запуску скрипту, щоб програма могла використовувати цей файл як вхідні дані.[8] Наприклад, якщо скрипт має шлях path/to/script і починається з рядка #! /bin/sh, то завантажувач програм запустить програму /bin/sh, передавши path/to/script як перший аргумент.
Рядок шебангу зазвичай ігнорується самим інтерпретатором, оскільки символ «#» є маркером коментаря у багатьох скриптових мовах; деякі інтерпретатори мов, які не використовують знак решітки для початку коментарів, все одно можуть ігнорувати рядок шебангу, розпізнаючи його призначення.[9]
Remove ads
Синтаксис
Узагальнити
Перспектива
Форма директиви інтерпретатора шебанг виглядає наступним чином:[8]
#! інтерпретатор [необов'язковий-аргумент]
де інтерпретатор — це абсолютний шлях до виконуваного файлу. Пробіл між #! та інтерпретатор є необов'язковим. Перед або після інтерпретатора може бути будь-яка кількість пробілів або символів табуляції. Необов'язковий-аргумент включає будь-які додаткові пробіли до кінця рядка.
У Linux файл, вказаний як інтерпретатор, може бути виконаний, якщо він має права на виконання та є одним із наступного:
- нативний виконуваний файл, наприклад, бінарний файл у форматі ELF;
- будь-який тип файлу, для якого інтерпретатор був зареєстрований через механізм binfmt_misc (наприклад, для запуску бінарних файлів Microsoft .exe за допомогою Wine);
- інший скрипт, що починається з шебангу.
У Linux та Minix інтерпретатор також може бути скриптом. Ланцюжок шебангів та обгорток (wrappers) створює безпосередньо виконуваний файл, який отримує зустрінуті скрипти як параметри у зворотному порядку. Наприклад, якщо файл /bin/A є виконуваним файлом у форматі ELF, файл /bin/B містить шебанг #! /bin/A optparam, а файл /bin/C містить шебанг #! /bin/B, то виконання файлу /bin/C призведе до виконання /bin/B /bin/C, що в кінцевому підсумку перетвориться на /bin/A optparam /bin/B /bin/C.
В операційних системах, похідних від Solaris та Darwin (наприклад, macOS), файл, зазначений як інтерпретатор, повинен бути виконуваним бінарним файлом і не може сам бути скриптом.[10]
Remove ads
Приклади
Деякі типові рядки шебангу:
#! /bin/sh— виконати файл за допомогою Bourne shell або сумісної оболонки, яка, як передбачається, знаходиться в каталозі /bin.#! /bin/bash— виконати файл за допомогою Bash.#! /usr/bin/pwsh— виконати файл за допомогою PowerShell.#! /usr/bin/env python3— виконати за допомогою інтерпретатора Python, використовуючи шлях пошуку програм env, щоб знайти його.#! /bin/false— нічого не робити, але повернути ненульовий код виходу, вказуючи на невдачу. Використовується для запобігання автономному виконанню файлу скрипту, призначеного для виконання в певному контексті, наприклад, командою.з sh/bash,sourceз csh/tcsh, або як файли .profile, .cshrc чи .login.
Рядки шебангу можуть включати специфічні опції, які передаються інтерпретатору. Однак реалізації відрізняються в поведінці парсингу опцій; для переносимості слід вказувати лише одну опцію без вбудованих пробілів.[11]
Remove ads
Призначення
Узагальнити
Перспектива
Директиви інтерпретатора дозволяють використовувати скрипти та файли даних як системні команди, приховуючи деталі їх реалізації від користувачів та інших програм, усуваючи необхідність вказувати інтерпретатор перед назвою скрипту в командному рядку.
Наприклад, розглянемо скрипт, що має початковий рядок #! /bin/sh -x. Його можна викликати просто вказавши шлях до нього, наприклад some/path/to/foo,[12] і деякі параметри, такі як bar та baz:
some/path/to/foo bar baz
У цьому випадку замість нього викликається /bin/sh з параметрами -x, some/path/to/foo, bar та baz, так ніби початкова команда була:
/bin/sh -x some/path/to/foo bar baz
Більшість інтерпретаторів роблять будь-які додаткові аргументи доступними для скрипту. Якщо /bin/sh є POSIX-сумісною оболонкою, то bar та baz представлені скрипту як масив позиційних параметрів "$@", і індивідуально як параметри "$1" та "$2" відповідно.
Оскільки початковий символ # використовується для введення коментарів у мові оболонки POSIX (і в мовах, зрозумілих багатьом іншим інтерпретаторам), весь рядок шебангу ігнорується інтерпретатором. Однак ігнорування рядка шебангу залежить від самого інтерпретатора, і не всі це роблять; тому скрипт, що складається з наступних двох рядків, просто виведе обидва рядки при запуску:
#! /bin/cat Hello world!
Переваги
У порівнянні з використанням глобальних списків асоціацій між розширеннями файлів та програмами-інтерпретаторами, метод директиви інтерпретатора дозволяє користувачам використовувати інтерпретатори, не відомі на глобальному системному рівні, і без прав адміністратора. Це також дозволяє вибирати конкретний інтерпретатор без перевантаження простору назв розширень імен файлів (де одне розширення може посилатися на більше ніж один тип файлу) і дозволяє змінювати мову реалізації скрипту без зміни синтаксису його виклику іншими програмами.
Переносимість
Узагальнити
Перспектива
Розташування програми
Шебанги повинні вказувати абсолютні шляхи (або шляхи відносно поточного робочого каталогу) до системних виконуваних файлів; це може викликати проблеми на системах, які мають нестандартну структуру файлової системи. Навіть якщо системи мають досить стандартні шляхи, цілком можливо, що варіанти однієї і тієї ж операційної системи мають різні розташування для бажаного інтерпретатора. 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, Bash (Bourne Again shell). Використання специфічного синтаксису bash при збереженні шебангу, що вказує на sh, також не є переносимим.[14]
Через це іноді потрібно редагувати рядок shebang після копіювання скрипта з одного комп'ютера на інший, оскільки шлях, який був закодований у скрипті, може не застосовуватися на новій машині, залежно від узгодженості попередніх правил розміщення інтерпретатора. З цієї причини, а також тому, що POSIX не стандартизує імена шляхів, POSIX не стандартизує цю функцію. [15] Інструмент GNU Autoconf може перевірити підтримку системи за допомогою макросу AC_SYS_INTERPRETER.[16]
Часто програма /usr/bin/env може бути використана для обходу цього обмеження, вводячи рівень непрямої адресації (indirection). #! супроводжується /usr/bin/env, за яким слідує бажана команда без повного шляху, як у цьому прикладі:
#!/usr/bin/env sh
Це працює в більшості випадків, оскільки шлях /usr/bin/env зазвичай використовується для утиліти env, і вона викликає перший sh, знайдений у змінній середовища $PATH користувача, зазвичай /bin/sh.
Використання #!/usr/bin/env призводить до непрямої адресації під час виконання, що потенційно може знизити безпеку системи; з цієї причини деякі коментатори рекомендують утриматися від його використання[17] у пакетному програмному забезпеченні, залишаючи його лише для "навчальних прикладів".
Розбиття аргументів
Аргументи команд розбиваються по-різному на різних платформах. Деякі системи не розбивають аргументи; наприклад, при запуску скрипту з першим рядком:
#!/usr/bin/env python3 -c
весь текст після першого пробілу розглядається як один аргумент, тобто python3 -c буде передано як один аргумент до /usr/bin/env, а не як два аргументи. До таких систем належать Linux[18][19] та Cygwin.
Іншим підходом є використання обгортки (wrapper). FreeBSD 6.0 (2005) ввела опцію -S для своєї утиліти env. Ця опція вказує env розділити рядок самостійно.[20] Утиліта GNU env з пакету coreutils 8.30 (2018) також включає цю функцію.[21] Хоча використання цієї опції зменшує проблему переносимості на стороні ядра через розділення, вона додає вимогу, щоб env підтримував це конкретне розширення.
Інтерпретація символів
Іншою проблемою є скрипти, що містять символ повернення каретки відразу після рядка шебангу, можливо, в результаті редагування в системі, яка використовує розриви рядків DOS (Microsoft Windows). Деякі системи інтерпретують символ повернення каретки як частину команди інтерпретатора, що призводить до повідомлення про помилку.[22]
Магічне число
Шебанг насправді є зручним для читання людиною екземпляром магічного числа у виконуваному файлі; магічним рядком байтів є 0x23 0x21, що є двосимвольним кодуванням в ASCII для #!. Це магічне число виявляється сімейством функцій "exec", які визначають, чи є файл скриптом або виконуваним бінарним файлом. Наявність shebang призведе до виконання зазначеного виконуваного файлу, зазвичай інтерпретатора мови скрипта. Стверджувалося[23], що деякі старі версії Unix очікують, що після звичайного shebang буде пробіл та похила риска (#! /), але це, схоже, не відповідає дійсності;[11] радше пробіли після shebang традиційно дозволялися, а іноді документувалися з пробілом, як описано в історичному електронному листі 1980 року нижче.
Символи шебангу представлені тими ж двома байтами в кодуваннях розширеного ASCII, включаючи UTF-8, який зазвичай використовується для скриптів у сучасних Unix-подібних системах. Однак файли UTF-8 можуть починатися з необов'язкового маркера послідовності байтів (BOM); якщо функція "exec" конкретно виявляє байти 0x23 та 0x21, то наявність BOM (0xEF 0xBB 0xBF) перед шебангом завадить виконанню інтерпретатора скрипту. Деякі джерела рекомендують не використовувати BOM у скриптах POSIX (Unix-подібних)[24] з цієї причини, а також для ширшої сумісності. Крім того, позначка порядку байтів не є необхідною в UTF-8, оскільки це кодування не має проблем з порядком байтів; вона служить лише для ідентифікації кодування як UTF-8.[24]
Remove ads
Етимологія
Назва шебанг (shebang) для характерних двох символів, ймовірно, походить від неточного стягнення слів SHArp bang або haSH bang, посилаючись на дві типові назви цих символів у Unix. Інша теорія щодо sh у shebang полягає в тому, що це походить від оболонки за замовчуванням sh, яка зазвичай викликається за допомогою шебангу.[25] Це використання було актуальним до грудня 1989 року,[26] і ймовірно раніше.
Remove ads
Історія
Узагальнити
Перспектива
Шебанг був введений Деннісом Рітчі між Виданням 7 та 8 у Bell Laboratories. Його також було додано до релізів BSD від Berkeley's Computer Science Research (присутній у версії 2.8BSD[27] та активований за замовчуванням у версії 4.2BSD). Оскільки Unix 8-го видання AT&T Bell Laboratories не був випущений для широкого загалу, перша широковідома поява цієї функції відбулася в BSD.
Відсутність директиви інтерпретатора, але підтримка скриптів оболонки, очевидна в документації Version 7 Unix 1979 року, [28] що натомість описує функцію оболонки Bourne, де файли з дозволом на виконання обробляються спеціально оболонкою, яка (іноді залежно від початкових символів у скрипті, таких як ":" або "#") створює підоболонку, яка інтерпретує та виконує команди, що містяться у файлі. У цій моделі скрипти поводяться як інші команди, лише якщо їх викликати з оболонки Bourne. Спроба безпосередньо виконати такий файл через власний системний виклик exec() операційної системи зазнає невдачі, що заважає скриптам поводитися однаково як звичайні системні команди.
Вдосконалені скрипти оболонки Version 8
У пізніших версіях Unix-подібних систем цю непослідовність було усунуто. Денніс Рітчі ввів підтримку директив інтерпретатора в ядрі у січні 1980 року для Version 8 Unix з наступним описом: [27]
Від uucp Чт 10 Січ 01:37:58 1980 > Від dmr Чт 10 Січ 04:25:49 1980 віддалено від дослідження Систему було змінено таким чином, що якщо файл, що виконується, починається з магічних символів #!, решта рядка розуміється як ім'я інтерпретатора для виконуваного файлу. Раніше (і фактично досі) оболонка виконувала значну частину цієї роботи; вона автоматично виконувалася на текстовому файлі з режимом виконання, коли ім'я текстового файлу вводилося як команда. Впровадження цієї функції в систему дає такі переваги. 1) Це робить скрипти оболонки більш схожими на справжні виконувані файли, оскільки вони можуть бути об'єктом 'exec'. 2) Якщо ви виконуєте 'ps' під час виконання такої команди, її справжнє ім'я відображається замість 'sh'. Так само, облік ведеться на основі справжнього імені. 3) Скрипти оболонки можуть бути set-user-ID.[a] 4) Простіше мати доступні альтернативні оболонки; наприклад, якщо вам подобається Berkeley csh, немає питань про те, яка оболонка має інтерпретувати файл. 5) Це дозволить іншим інтерпретаторам плавніше вписатися. Щоб скористатися цією чудовою можливістю, поставте #! /bin/sh на лівому краю першого рядка ваших скриптів оболонки. Пробіли після ! допустимі. Використовуйте повний шлях (пошук не виконується). Наразі весь рядок обмежений 16 символами, але це обмеження буде збільшено.
Функція безіменного скрипта оболонки
Творець функції не дав їй ім'я, проте:[30]
Від: "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.[31]
Цей механізм дозволяє використовувати скрипти практично в будь-якому контексті, де можуть бути звичайні скомпільовані програми, включаючи повноцінні системні програми та навіть як інтерпретатори інших скриптів. Однак, як застереження, деякі ранні версії підтримки ядра обмежували довжину директиви інтерпретатора приблизно 32 символами (лише 16 у першій реалізації), не могли розділити ім'я інтерпретатора від будь-яких параметрів у директиві або мали інші особливості. Крім того, деякі сучасні системи дозволяють обмежувати або вимикати весь механізм з міркувань безпеки (наприклад, підтримка set-user-id була вимкнена для скриптів у багатьох системах).
Зауважте, що навіть у системах з повною підтримкою ядром магічного числа #! деякі скрипти, яким бракує директив інтерпретатора (хоча зазвичай все ще вимагають дозволу на виконання), все ще можна запускати завдяки застарілій обробці скриптів оболонки Bourne, яка все ще присутня в багатьох її сучасних нащадках. Потім скрипти інтерпретуються оболонкою користувача за замовчуванням.
Remove ads
Див. також
- binfmt_misc
- CrunchBang Linux
- File association
- URI fragment
Примітки
Посилання
Wikiwand - on
Seamless Wikipedia browsing. On steroids.
Remove ads
