Мені здається, що файли працюють однаково без цього рядка.
Мені здається, що файли працюють однаково без цього рядка.
Відповіді:
Якщо у вас встановлено кілька версій Python, /usr/bin/env
переконайтеся, що використаний інтерпретатор є першим у вашому середовищі $PATH
. Альтернативою було б твердий код чогось подібного #!/usr/bin/python
; це нормально, але менш гнучко.
У Unix виконуваний файл, призначений для інтерпретації, може вказувати, який інтерпретатор використовувати, маючи #!
на початку першого рядка, за яким слід інтерпретатор (та будь-які прапори, які можуть знадобитися).
Якщо ви говорите про інші платформи, звичайно, це правило не застосовується (але ця "лінія шебанг" не шкодить, і допоможе, якщо ви коли-небудь скопіюєте цей скрипт на платформу з базою Unix, наприклад, Linux, Mac тощо).
chmod +x myscript.py
), а потім запускаючи безпосередньо:, ./myscript.py
а не просто python myscript.py
.
env
дає максимальну гнучкість в тому, що користувач може вибрати інтерпретатора, який буде використовувати, змінивши PATH. Часто ця гнучкість не потрібна, але недоліком є те, що Linux, наприклад, не може використовувати ім'я сценарію для імені процесу ps
і повертається до "python". Наприклад, упакуючи програми python для дистрибутивів, я б радив не використовувати env
.
py
Пускова програма може використовувати лінію shebang у Windows. Він включений в Python 3.3 або його можна встановити самостійно .
/usr/bin/env: Key has expired
через багато годин.
Це називається лінією shebang . Як пояснює запис у Вікіпедії :
Під час обчислень, шебанг (його також називають хешбанг, хешпінг, фунт баг або крахбанг) посилається на символи "#!" коли вони є першими двома символами директиви інтерпретатора як перший рядок текстового файлу. В операційній системі, подібній Unix, завантажувач програм приймає наявність цих двох символів як ознаку того, що файл є сценарієм, і намагається виконати цей скрипт за допомогою інтерпретатора, визначеного рештою першого рядка у файлі.
Дивіться також запис у FAQ про Unix .
Навіть у Windows, де лінія shebang не визначає запуск інтерпретатора, ви можете передати варіанти інтерпретатору, вказавши їх на лінії shebang. Мені здається корисним зберігати загальну лінію shebang в разових сценаріях (таких, як ті, про які я пишу, відповідаючи на запитання на SO), тому я можу швидко перевірити їх як у Windows, так і в ArchLinux .
Утиліта окр дозволяє виконати команду на шляху:
Перший аргумент, що залишився, вказує назву програми для виклику; його шукають відповідно до
PATH
змінної середовища. Будь-які інші аргументи передаються як аргументи до цієї програми.
Розгорнувши трохи інші відповіді, ось невеликий приклад того, як ваші сценарії командного рядка можуть потрапити в проблему шляхом обережного використання /usr/bin/env
рядків shebang:
$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py
Traceback (most recent call last):
File "./my_script.py", line 2, in <module>
import json
ImportError: No module named json
Модуль json не існує в Python 2.5.
Один із способів уберегти від подібних проблем - це використання перетворених імен команд python, які зазвичай встановлюються для більшості Pythons:
$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"
Якщо вам просто потрібно розрізнити Python 2.x і Python 3.x, останні випуски Python 3 також містять python3
назву:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
which python
повертається /usr/bin/python
, локальний шлях до каталогу може бути жорстокий: #!/usr/bin/python
. Але це менш гнучко, ніж те, #!/usr/bin/env python
що має глобальне застосування.
Для того щоб запустити скрипт python, нам потрібно сказати оболонці про три речі:
Шебанг #!
виконує (1.). Шебанг починається з а, #
оскільки #
персонаж є маркером коментарів у багатьох мовах сценаріїв. Перекладач автоматично ігнорує вміст рядка shebang.
У env
команді виробляється (2) і (3). Цитувати "grawity"
Поширене використання
env
команди - це запуск інтерпретаторів, використовуючи той факт, що env шукатиме $ PATH для команди, яку йому сказано запустити. Оскільки лінія shebang вимагає уточнення абсолютного шляху, а оскільки розташування різних інтерпретаторів (perl, bash, python) може сильно відрізнятися, звичайно використовувати:
#!/usr/bin/env perl
замість того, щоб намагатися вгадати, чи це / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl, / fileserver / usr / bin / perl, або / home / MrDaniel / usr / bin / perl в системі користувача ...З іншого боку, env майже завжди є в / usr / bin / env. (За винятком випадків, коли його немає; деякі системи можуть використовувати / bin / env, але це досить рідкісний випадок і трапляється лише в системах, що не є Linux.)
Можливо, ваше питання в цьому сенсі:
Якщо ви хочете використовувати: $python myscript.py
Ця лінія вам зовсім не потрібна. Система викличе python, а потім інтерпретатор python запустить ваш сценарій.
Але якщо ви маєте намір використовувати: $./myscript.py
Викликаючи його безпосередньо як звичайну програму або скрипт bash, вам потрібно написати цей рядок, щоб вказати системі, яку програму використовувати для його запуску (а також зробити її виконуваною chmod 755
)
exec
Системний виклик в Linux ядро розуміє shebangs ( #!
) спочатку
Коли ви займаєтеся басом:
./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, правильно вводить його в пам'ять і запускає новий процес з ним. Дивіться також: Як ядро отримує виконуваний бінарний файл, що працює під Linux?
Нарешті, ви можете додати власні обробники шебанг із binfmt_misc
механізмом. Наприклад, ви можете додати спеціальний обробник .jar
файлів . Цей механізм навіть підтримує обробники за допомогою розширення файлу. Інша програма полягає у прозорому запуску виконуваних файлів іншої архітектури за допомогою QEMU .
Я не думаю, що POSIX не вказує shebangs: https://unix.stackexchange.com/a/346214/32558 , хоча це згадується в розділах обґрунтування, а також у формі "якщо виконувані сценарії підтримуються системою, щось може трапляються ». macOS і FreeBSD також, здається, впроваджують його.
PATH
мотивація пошуку
Ймовірно, однією з великих мотивацій існування шебангів є той факт, що в Linux ми часто хочемо запускати команди PATH
так само:
basename-of-command
замість:
/full/path/to/basename-of-command
Але тоді, без механізму shebang, як би Linux знав, як запускати кожен тип файлів?
Жорстке кодування розширення в командах:
basename-of-command.py
або здійснення пошуку PATH на кожному перекладачі:
python basename-of-command
це було б можливим, але в цьому є головна проблема, що все порушується, якщо ми коли-небудь вирішимо переформувати команду на іншу мову.
Шебангс прекрасно вирішує цю проблему.
Технічно в Python це лише рядок коментарів.
Цей рядок використовується лише в тому випадку, якщо ви запускаєте скрипт py з оболонки (з командного рядка). Це відомо як " Шебанг !" , і використовується в різних ситуаціях, а не лише зі скриптами Python.
Тут він доручає оболонці запустити конкретну версію Python (подбати про решту файлу.
py.exe
. Це частина стандартної установки Python.
Основна причина цього - зробити скрипт портативним для всіх операційних систем.
Наприклад, під mingw сценарії python використовують:
#!/c/python3k/python
а під дистрибутивом GNU / Linux це:
#!/usr/local/bin/python
або
#!/usr/bin/python
і за найкращою комерційною системою SW / HW всіх (OS / X), це:
#!/Applications/MacPython 2.5/python
або на FreeBSD:
#!/usr/local/bin/python
Однак усі ці відмінності можуть зробити скрипт портативним для всіх, використовуючи:
#!/usr/bin/env python
/usr/bin/python
. В Linux, встановлений системою Python, також майже напевно /usr/bin/python
(я ще нічого не бачив і це не мало б сенсу). Зверніть увагу, що можуть бути системи, яких немає /usr/bin/env
.
python
- це не портативний портал, а інтерпретатор Python за замовчуванням. Arch Linux за замовчуванням на Python 3 тривалий час, і, можливо, дистрибутиви думають і про це, тому що Python 2 підтримується лише до 2020 року.
Напевно, має сенс підкреслити одне, що найбільше пропустили, що може завадити негайному зрозумінню. Під час введення python
терміналу ви зазвичай не надаєте повний шлях. Натомість виконуваний файл шукає PATH
змінну середовища. У свою чергу, коли ви хочете виконати програму Python безпосередньо, /path/to/app.py
потрібно сказати оболонці, який інтерпретатор використовувати (через хешбанг , що пояснюють інші учасники).
Хашбанг очікує повного шляху до перекладача. Таким чином, щоб безпосередньо запустити вашу програму Python, ви повинні надати повний шлях до бінарних файлів Python, який значно відрізняється, особливо з урахуванням використання virtualenv . Для вирішення проблеми переносимості використовується хитрість /usr/bin/env
. Остання спочатку призначена для зміни середовища на місці та виконання команди в ньому. Якщо ніяких змін не передбачено, він запускає команду в поточному середовищі, що ефективно призводить до того ж PATH
пошуку, який виконує трюк.
Це умовна оболонка, яка повідомляє оболонці, яка програма може виконати сценарій.
#! / usr / bin / env python
вирішує шлях до бінарного файлу Python.
Рекомендований спосіб, запропонований у документації:
2.2.2. Виконані сценарії Python
У системах BSD'ish Unix сценарії Python можна зробити безпосередньо виконуваними, як сценарії оболонки, шляхом розміщення рядка
#! /usr/bin/env python3.2
від http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Ви можете спробувати це питання, використовуючи virtualenv
Ось тест.py
#! /usr/bin/env python
import sys
print(sys.version)
Створення віртуальних середовищ
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
активуйте кожне середовище, а потім перевірте відмінності
echo $PATH
./test.py
Він просто вказує, який інтерпретатор ви хочете використовувати. Щоб зрозуміти це, створіть файл через термінал touch test.py
, ввівши в нього наступне:
#!/usr/bin/env python3
print "test"
і зробіть так, chmod +x test.py
щоб ваш сценарій виконувався. Після цього, коли ви будете робити, ./test.py
ви повинні отримати повідомлення про помилку:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
тому що python3 не підтримує оператора друку.
Тепер ідіть і змініть перший рядок свого коду на:
#!/usr/bin/env python2
і він буде працювати, друкуючи test
до stdout, тому що python2 підтримує оператор друку. Отже, тепер ви дізналися, як переключатися між інтерпретаторами сценаріїв.
Мені здається, що файли працюють однаково без цього рядка.
Якщо так, то, можливо, ви запускаєте програму Python в Windows? Windows не використовує цей рядок - натомість використовує розширення імені файлу для запуску програми, пов'язаної з розширенням файлу.
Однак у 2011 році був розроблений "запуск Python", який (певною мірою) імітує цю поведінку Linux для Windows. Це обмежується лише вибором інтерпретатора Python, наприклад, для вибору між Python 2 та Python 3 у системі, де встановлено обидва. Запускається програма, необов'язково встановлюється як py.exe
при встановленні Python, і може бути пов’язана з .py
файлами, щоб пускач перевірив цей рядок і в свою чергу запустив вказану версію інтерпретатора Python.
$ python myscript.py
.
Це розуміється як більше історичної інформації, ніж «реальна» відповідь.
Пам'ятайте , що ще в день ви мали БАГАТО UNIX - подібні операційні системам , в яких дизайнери все мав своє власне уявлення про те, де покласти речі, а іноді і не включає в себе Python, Perl, Bash, або багато іншого GNU / Open Source матеріалу на все .
Це стосувалося навіть різних дистрибутивів Linux. У Linux - pre-FHS [1] - у вас може бути python в / usr / bin / або / usr / local / bin /. Або він може бути не встановлений, тому ви створили свій власний і помістили його в ~ / bin
Solaris був найгіршим, над чим я коли-небудь працював, частково як перехід від Berkeley Unix до System V. Ви могли б завершити роботу в / usr /, / usr / local /, / usr / ucb, / opt / etc. Це могло зробити для деяких дійсно довгих шляхів. У мене є запам'ятовування матеріалів із Sunfreeware.com, що встановлюють кожен пакунок у власному каталозі, але я не можу згадати, чи він пов'язував двійкові файли у / usr / bin чи ні.
О, а інколи / usr / bin був на сервері NFS [2].
Тож env
утиліта була розроблена для вирішення цього питання.
Тоді ви могли писати #!/bin/env interpreter
і до тих пір, поки шлях був належним, речі мали розумні шанси запуститись. Звичайно, розумно означало (для Python і Perl) , що ви також встановити відповідні змінні оточення. Для bash / ksh / zsh це просто працювало.
Це було важливо, тому що люди проходили навколо скриптів оболонки (наприклад, perl та python), і якщо вам важко закодовано / usr / bin / python на вашій робочій станції Red Hat Linux, на SGI це не вдалося зламати ... ну, ні , Я думаю, що IRIX поставив python в потрібне місце. Але на станції Sparc вона може взагалі не працювати.
Я сумую за своїм спарком. Але не багато. Гаразд, тепер у мене є тролінг по E-Bay. Бастажі.
[1] Стандарт ієрархії файлової системи. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Так, а іноді люди все ще роблять подібні речі. І ні, я не носив ні репи, ні цибулі на поясі.
Якщо ви запускаєте свій скрипт у віртуальному середовищі, скажімо venv
, тоді виконання which python
під час роботи venv
відобразить шлях до інтерпретатора Python:
~/Envs/venv/bin/python
Зауважте, що ім'я віртуального середовища вбудовано в шлях до інтерпретатора Python. Тому жорстке кодування цього шляху у вашому сценарії спричинить дві проблеми:
Тому, щоб додати відповідь Джонатана , ідеальним шебангом є #!/usr/bin/env python
не тільки портативність через ОС, а й переносність у віртуальних середовищах!
Враховуючи проблеми переносимості між python2
і python3
, завжди слід вказувати будь-яку версію, якщо ваша програма сумісна з обома.
Деякі дистрибуції вже деякий час python
посилаються на посилання python3
- не покладайтесь на python
це python2
.
На цьому наголошує PEP 394 :
Щоб допустити відмінності між платформами, увесь новий код, який потребує виклику інтерпретатора Python, не повинен вказувати python, а навпаки, повинен визначати або python2 або python3 (або більш конкретні версії python2.x та python3.x; див. Примітки про міграцію ) . Це розрізнення повинно бути зроблено в шебангах, при виклику із сценарію оболонки, при виклику через виклик system () або при виклику в будь-якому іншому контексті.
Це дозволяє вибрати виконаний файл, який ви хочете використовувати; що дуже зручно, якщо, можливо, у вас є кілька встановлень python, і різні модулі в кожній і хочете вибрати. напр
#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3
if [ -x $PREFERRED_PYTHON ]; then
echo Using preferred python $ALTERNATIVE_PYTHON
exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
echo Using alternative python $ALTERNATIVE_PYTHON
exec $ALTERNATIVE_PYTHON "$0" "$@"
else
echo Using fallback python $FALLBACK_PYTHON
exec python3 "$0" "$@"
fi
exit 127
'''
__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())
це говорить сценарію, де знаходиться каталог python!
#! /usr/bin/env python
#!/usr/bin/env python
вгорі.