В bashабо sh, я припускаю , що все , що починається з #це коментар .
Але в bashсценаріях ми пишемо:
#!/bin/bash
А в сценаріях Python є:
#!/bin/python
Чи означає це, що #сам по собі є коментарем, тоді #!як ні?
В bashабо sh, я припускаю , що все , що починається з #це коментар .
Але в bashсценаріях ми пишемо:
#!/bin/bash
А в сценаріях Python є:
#!/bin/python
Чи означає це, що #сам по собі є коментарем, тоді #!як ні?
Відповіді:
#!Лінія використовується , перш ніж скрипт запускається, то ігнорується при виконанні сценарію.Ви запитуєте, в чому різниця між рядком shebang та звичайним коментарем.
Рядок, що починається з #!- це так само коментар, як і будь-який інший рядок, який починається з #. Це справедливо, якщо #!це перший рядок файлу чи деінде. #!/bin/sh має ефект , але його не читає сам перекладач .
#це не коментар у всіх мовах програмування, але, як ви знаєте, це коментар у оболонках у стилі Борна, включаючи shта bash(як і більшість оболонок у стилі Борна, як csh). Це також коментар у Python . І це коментар до різноманітних файлів конфігурації, які насправді взагалі не є сценаріями (як /etc/fstab).
Припустимо, сценарій оболонки починається з #!/bin/sh. Це коментар, і інтерпретатор (оболонка) ігнорує все в рядку після #символу.
Мета #!рядка - не давати інформацію перекладачеві. Мета #!рядка - повідомити операційній системі (або будь-який процес, який запускає інтерпретатор), що використовувати як інтерпретатор .
Якщо ви викликаєте скрипт як виконуваний файл, наприклад, запустивши ./script.sh, система звертається до першого рядка, щоб побачити, чи починається з нього #!, а потім нуль або більше пробілів, а потім команда. Якщо це так, він виконує цю команду з назвою скрипту як свого аргументу. У цьому прикладі він працює /bin/sh script.sh(або, технічно, /bin/sh ./script.sh).
Якщо ви викликаєте скрипт, чітко зателефонувавши до інтерпретатора, #!рядок ніколи не проводиться. Отже, якщо ви запустите sh script.sh, перший рядок не має ефекту. Якщо script2.shперший рядок #!/usr/games/nibbles, запущений sh script2.shне буде намагатися відкрити скрипт в nibbles(але ./script2.shбуде).
Ви помітите, що в жодному випадку розширення скрипта ( .sh), якщо воно є, не впливає на його виконання. У Unix-подібній системі це зазвичай не впливає на те, як виконується сценарій. У деяких інших системах, наприклад Windows, система #!shebang може повністю ігноруватися системою, а розширення може визначати, що виконує сценарії. (Це не означає, що вам потрібно давати розширення для сценаріїв, але це одна з причин, чому, якщо ви це зробите, вони повинні бути правильними.)
#!був обраний для того, щоб служити цій меті саме тому, що # починається коментар. #!Лінія для системи, а НЕ перекладач, і він повинен бути проігнорований інтерпретатором.
Ви (спочатку) сказали, що використовуєте #!/bin/shдля bashсценаріїв. Ви повинні зробити це лише в тому випадку, якщо сценарій не вимагає bashрозширень sh. shне завжди є посиланням на bash. Часто, в тому числі на всіх віддалених останніх системах Debian і Ubuntu , shє символьним посиланням на dash.
Ви також сказали (у першій версії свого запитання, перш ніж редагувати), що запускаєте сценарії Python #!/bin/sh read by the interpretor. Якщо ви маєте на увазі це буквально, то вам обов'язково слід припинити це робити. Якщо hello.pyпочинається з цього рядка, запуск ./hello.pyвиконує:
/bin/sh read by the interpretor hello.py
/bin/shспробує виконати скрипт, який називається read(з by the interpretor hello.pyйого аргументами), read(сподіваємось) не знайдеться, і ваш сценарій Python ніколи не побачить інтерпретатора Python.
Якщо ви робите цю помилку, але не маєте проблеми, яку я описую, ви, ймовірно, посилаєтесь на ваші скрипти Python, чітко вказавши інтерпретатора (наприклад, python hello.py), викликаючи ігнорування першого рядка. Коли ви розповсюджуєте свої сценарії іншим або використовуєте їх довгий час пізніше, можливо, не буде зрозуміло, що це потрібно їм. Найкраще їх виправити зараз. Або принаймні повністю видаліть перший рядок, так що, коли вони не зможуть запустити ./повідомлення про помилку, матиме сенс.
Для сценаріїв Python, якщо ви знаєте, де перекладач Python знаходиться (або буде), ви можете записати #!рядок так само:
#!/usr/bin/python
Або, якщо це сценарій Python 3, вам слід вказати python3, оскільки pythonце майже завжди Python 2 :
#!/usr/bin/python3
Однак проблема полягає в тому, що, як /bin/shпередбачається, існує завжди і /bin/bashмайже завжди існує в системах, де bashпоставляється з ОС, Python може існувати в різних місцях.
Тому багато програмістів Python використовують це замість цього:
#!/usr/bin/env python
(Або #!/usr/bin/env python3для Python 3.)
Це змушує сценарій розраховувати на envте, щоб опинитися у "правильному місці", а не покладатися на pythonправильне місце. Це добре, адже:
envмайже завжди знаходиться в с /usr/bin.python повинен запустити ваш сценарій, той, який з’являється першим у PATH. Починаючи hello.pyз #!/usr/bin/env pythonmake ./hello.pyrun /usr/bin/env python hello.py, що (практично) еквівалентно бігу python hello.py.Причина, яку ви не можете використовувати, #!pythonполягає в тому, що:
/).python в поточному каталозі . Пошук шляху, коли команда не містить косу рису, є специфічною поведінкою оболонки.Інколи Python або інший скрипт, який не є скриптом оболонки, матиме рядок shebang, починаючи з того, #!/bin/sh ...де ...є якийсь інший код. Іноді це правильно, оскільки є деякі способи викликати сумісну з Bourne оболонку ( sh) з аргументами, щоб змусити її викликати інтерпретатора Python. (Один із аргументів, мабуть, міститиме python.) Однак для більшості цілей #!/usr/bin/env pythonпростіше, елегантніше та швидше працювати так, як вам хочеться.
Багато мов програмування та сценаріїв, а також деякі інші формати файлів використовують #як коментар. Для будь-якого з них файл мовою може бути запущений програмою, яка сприймає його як аргумент, вказавши програму в першому рядку після #!.
У деяких мовах програмування #зазвичай це не коментар, але, як особливий випадок, перший рядок ігнорується, якщо він починається з #!. Це полегшує використання #!синтаксису, хоча #інше не робить коментар у рядку.
Хоча це менш інтуїтивно, будь-який файл, формат якого може вмістити перший рядок, починаючи з #!наступного повного шляху виконуваного файлу, може мати рядок shebang. Якщо ви це зробите, а файл позначений виконуваним, ви можете запустити його як програму ... змусивши його відкритись як документ.
Деякі програми використовують цю поведінку навмисно. Наприклад, у VMware .vmxфайли визначають віртуальні машини. Ви можете «запустити» віртуальну машину так, ніби це сценарій, тому що ці файли позначені виконуваним і мають рядок shebang, що призводить до їх відкриття в утиліті VMware.
rmвидаляє файли. Це не сценарна мова. Однак файл, який запускається #!/bin/rmі позначений виконуваним, можна запустити, а коли ви запустите його, rmвикликається на ньому, видаливши його.
Це часто розуміється як "файл видаляє себе". Але файл насправді не працює. Це більше схоже на ситуацію, описану вище для .vmxфайлів.
Тим не менше, оскільки #!рядок полегшує запуск простої команди (включаючи аргументи командного рядка), ви можете виконати деякі сценарії таким чином. Як простий приклад "сценарію", більш складного, ніж #!/bin/rm, розглянемо:
#!/usr/bin/env tee -a
Це вводить інтерактивне введення користувача, повторює його назад в користувач по черзі та додає його до кінця файлу "скрипт".
Корисно? Не надто. Концептуально цікавий? Повністю! Так. (Дещо.)
Сценарії / програми, які є декількома мовами одночасно , наприклад, для імітації функціональності хешбангу в ОС, у яких його не було .
(Ці програми називаються поліглотами , але це не слід плутати з іншим сенсом поліглоту в розробці програмного забезпечення , програми / проекту, де різні частини написані різними мовами.)
Метакоманди в QBasic / QuickBASIC, які сигналізували компілятору (для компільованого коду) варіанти генерації коду, але були частиною коментарів і, таким чином, ігнорувались під час фактичної компіляції / інтерпретації.
-xпрапор Пітонів ?
-x"пропустити [s] перший рядок ..." 2-й рядок 1замість нумерується 2, 3-й рядок 2замість 3і т. д. Тому не слід використовувати цей прапор. ;) -xпризначений для сценаріїв на не-Unix-подібних ОС, у яких синтаксис, схожий на шебанг, не починається з #(таким чином, це не коментар Python).
perl script.plпроти ./script.pl) , то інтерпретатор буде читати рядок кубла для синтаксичного аналізу прапорів , таких як -w. Однак не рекомендується покладатися на цю функцію.
Шебанг - це послідовність символів, що складається з знака числа символів та знака оклику (наприклад, "#!"), Коли він зустрічається як два початкових символи в початковому рядку сценарію.
Під операційними системами * nix, коли виконується сценарій, починаючи з шебанга, програма завантажувача аналізує решту початкового рядка сценарію як директива інтерпретатора; задана програма інтерпретатора запускається замість цього, передаючи їй як аргумент шлях, який був спочатку використаний при спробі запуску сценарію. Наприклад, якщо сценарій названий зі шляху "шлях / до / ваш-скрипт", і він починається з наступного рядка:
#!/bin/sh
то завантажувач програми доручається запустити програму "/ bin / sh" замість цього, наприклад, оболонки Bourne або сумісної оболонки, передаючи "шлях / до / ваш-скрипт" в якості першого аргументу.
Відповідно, його сценарій іменується шляхом "шлях / до / python-script", і він починається з наступного рядка:
#!/bin/python
потім завантаженій програмі доручається запустити програму "/ bin / python" замість, наприклад, інтерпретатора Python, передаючи "шлях / до / python-script" в якості першого аргументу.
Якщо коротко, "#" прокоментує рядок, тоді як послідовність символів "#!" виникають як перші два символи в початковому рядку сценарію, мають значення, окреслені вище.
Докладніше див. Чому деякі сценарії починаються з #! ...?
Джерело: Деякі розділи цієї відповіді виведені (з незначною модифікацією) із Shebang (Unix) в англійській Вікіпедії (від авторів Wikipedia ). Ця стаття ліцензована під CC-BY-SA 3.0 , подібно до вмісту користувача тут в АС, тому таке виведення дозволено з атрибуцією.
#!називається shebangколи, коли це відбувається як два початкові символи в початковому рядку сценарію. Він використовується в скриптах для позначення перекладача для виконання. Значення shebangдля операційної системи (ядра), а не для оболонки; тому це не буде трактуватися як коментар.
Люб’язно: http://en.wikipedia.org/wiki/Shebang_%28Unix%29
Загалом, якщо файл виконується, але насправді це не виконується (двійкова) програма, і такий рядок присутній, програма, зазначена після #! починається з імені сценарію та всіх його аргументів. Ці два символи # і! повинні бути перші два байти у файлі!
Детальна інформація: http://wiki.bash-hackers.org/scripting/basics#the_shebang
Ні, він використовується лише при execсистемному виклику ядра Linux і трактується як коментар інтерпретатора
Коли ви займаєтеся басом:
./something
в Linux це викликає execсистемний виклик шляхом ./something.
Цей рядок ядра викликає файл, переданий на адресу exec: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Він читає найперші байти файлу і порівнює їх #!.
Якщо порівняння вірно, то решта рядка аналізується ядром Linux, що робить ще один execвиклик із шляхом /usr/bin/env pythonта поточним файлом як перший аргумент:
/usr/bin/env python /path/to/script.py
і це працює для будь-якої мови сценаріїв, яка використовується #як символ коментаря.
І так, ви можете зробити нескінченну петлю за допомогою:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash розпізнає помилку:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#! просто буває читатими людиною, але цього не потрібно.
Якщо файл починався з різних байтів, то execсистемний виклик використовував би інший обробник. Інший найважливіший вбудований обробник призначений для виконуваних файлів ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305, який перевіряє наявність байтів 7f 45 4c 46(що також буває людиною) читабельна для .ELF). Давайте підтвердимо, що прочитавши 4 перших байта /bin/ls, який є виконуваним ELF:
head -c 4 "$(which ls)" | hd
вихід:
00000000 7f 45 4c 46 |.ELF|
00000004
Отже, коли ядро бачить ці байти, воно бере файл ELF, правильно вводить його в пам'ять і починає новий процес з ним. Дивіться також: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Нарешті, ви можете додати власні обробники шебанг із binfmt_miscмеханізмом. Наприклад, ви можете додати спеціальний обробник .jarфайлів . Цей механізм навіть підтримує обробники за допомогою розширення файлу. Інша програма полягає у прозорому запуску виконуваних файлів іншої архітектури за допомогою QEMU .
Я не думаю, що POSIX не вказує shebangs: https://unix.stackexchange.com/a/346214/32558 , хоча це вказується в розділах обґрунтування, а також у формі "якщо виконувані сценарії підтримуються системою, щось може трапляються ».
#include. Там теж#це не означає як коментар.