В 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 python
make ./hello.py
run /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
. Там теж#
це не означає як коментар.