Wydaje mi się, że pliki działają tak samo bez tej linii.
Wydaje mi się, że pliki działają tak samo bez tej linii.
Odpowiedzi:
Jeśli masz zainstalowanych kilka wersji Pythona, /usr/bin/env
upewnij się, że użyty interpreter będzie pierwszym w twoim środowisku $PATH
. Alternatywą byłoby hardcode coś takiego #!/usr/bin/python
; to jest ok, ale mniej elastyczne.
W Uniksie plik wykonywalny , który ma być interpretowany, może wskazywać, jakiego interpretera użyć, umieszczając #!
na początku pierwszego wiersza, a za nim interpreter (i wszelkie potrzebne flagi).
Jeśli mówisz o innych platformach, oczywiście ta zasada nie ma zastosowania (ale ta „linia shebang” nie szkodzi i pomoże, jeśli kiedykolwiek skopiujesz ten skrypt na platformę z bazą Unix, taką jak Linux, Mac itp.).
chmod +x myscript.py
), a następnie uruchamianie bezpośrednio ./myscript.py
:, a nie tylko python myscript.py
.
env
daje maksymalną elastyczność, ponieważ użytkownik może wybrać tłumacza, który będzie używany, zmieniając ŚCIEŻKĘ. Często ta elastyczność nie jest wymagana, ale wadą jest to, że na przykład Linux nie może użyć nazwy skryptu dla nazwy procesu ps
i powraca do „python”. Na przykład przy pakowaniu aplikacji Pythona dla dystrybucji radzę nie używać env
.
py
program uruchamiający może korzystać z linii shebang w systemie Windows. Jest zawarty w Pythonie 3.3 lub można go zainstalować niezależnie .
/usr/bin/env: Key has expired
po wielu godzinach proces umierał z tą wiadomością .
To się nazywa linia shebang . Jak wyjaśnia wpis w Wikipedii :
W informatyce shebang (zwany również hashbangiem, hashplingiem, funtem lub crunchbangiem) odnosi się do znaków „#!” gdy są to pierwsze dwa znaki w dyrektywie interpretera jako pierwsza linia pliku tekstowego. W systemie operacyjnym uniksopodobnym moduł ładujący pobiera obecność tych dwóch znaków jako wskazanie, że plik jest skryptem, i próbuje wykonać ten skrypt za pomocą interpretera określonego przez resztę pierwszego wiersza pliku.
Zobacz także wpis FAQ Unix .
Nawet w systemie Windows, w którym linia shebang nie określa uruchomionego interpretera, można przekazać opcje do interpretera, określając je w linii shebang. Uważam, że przydatne jest utrzymywanie ogólnej linii shebang w jednorazowych skryptach (takich jak te, które piszę, odpowiadając na pytania dotyczące SO), dzięki czemu mogę szybko przetestować je zarówno w systemie Windows, jak i ArchLinux .
Narzędzie env pozwala na wywołanie polecenia na ścieżce:
Pierwszy pozostały argument określa nazwę programu do wywołania; jest wyszukiwane zgodnie ze
PATH
zmienną środowiskową. Wszelkie pozostałe argumenty są przekazywane jako argumenty do tego programu.
Rozwijając nieco inne odpowiedzi, oto mały przykład tego, jak skrypty wiersza poleceń mogą wpaść w kłopoty przez nieumyślne użycie /usr/bin/env
linii 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
Moduł json nie istnieje w Pythonie 2.5.
Jednym ze sposobów ochrony przed tego rodzaju problemami jest użycie wersjonowanych nazw poleceń python, które są zwykle instalowane z większością Pythonów:
$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"
Jeśli potrzebujesz tylko odróżnić Python 2.x i Python 3.x, najnowsze wydania Python 3 również zawierają python3
nazwę:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
which python
wróci /usr/bin/python
, lokalna ścieżka do katalogu może być ciężko kodowane: #!/usr/bin/python
. Ale jest to mniej elastyczne niż #!/usr/bin/env python
ma to zastosowanie globalne.
Aby uruchomić skrypt Pythona, musimy powiedzieć powłoce trzy rzeczy:
Shebang #!
wykonuje (1.). Shebang zaczyna się od, #
ponieważ #
znak jest znacznikiem komentarza w wielu językach skryptowych. Treść linii shebang jest zatem automatycznie ignorowana przez tłumacza.
W env
realizuje polecenie (2) i (3). Cytując „grawitację”,
Typowym zastosowaniem tego
env
polecenia jest uruchamianie interpreterów, wykorzystując fakt, że env przeszuka $ PATH dla polecenia, które ma zostać uruchomione. Ponieważ linia shebang wymaga podania bezwzględnej ścieżki, a lokalizacja różnych interpretatorów (perl, bash, python) może się bardzo różnić, często używa się:
#!/usr/bin/env perl
zamiast zgadywać, czy jest to / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl, / fileserver / usr / bin / perl lub / home / MrDaniel / usr / bin / perl w systemie użytkownika ...Z drugiej strony, env prawie zawsze znajduje się w / usr / bin / env. (Z wyjątkiem przypadków, gdy tak nie jest; niektóre systemy mogą używać / bin / env, ale jest to dość rzadka okazja i zdarza się tylko w systemach innych niż Linux).
Być może twoje pytanie brzmi w tym sensie:
Jeśli chcesz użyć: $python myscript.py
W ogóle nie potrzebujesz tej linii. System wywoła Python, a następnie interpreter Pythona uruchomi skrypt.
Ale jeśli zamierzasz użyć: $./myscript.py
Wywołując go bezpośrednio jak zwykły program lub skrypt bash, musisz napisać ten wiersz, aby określić w systemie, którego programu użyć, aby go uruchomić (a także umożliwić wykonanie go za pomocą chmod 755
)
exec
Wywołanie systemowe jądra Linux rozumie shebangs ( #!
) natywnie
Kiedy robisz na bash:
./something
w Linuksie wywołuje to wywołanie exec
systemowe ze ścieżką ./something
.
Ta linia jądra zostaje wywołana w pliku przekazanym do exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Odczytuje pierwsze bajty pliku i porównuje je #!
.
Jeśli porównanie jest prawdziwe, reszta linii jest analizowana przez jądro Linuksa, które wykonuje kolejne exec
wywołanie ze ścieżką /usr/bin/env python
i bieżącym plikiem jako pierwszym argumentem:
/usr/bin/env python /path/to/script.py
i działa to na każdy język skryptowy, który używa #
jako znaku komentarza.
I tak, możesz wykonać nieskończoną pętlę za pomocą:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash rozpoznaje błąd:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
akurat jest czytelny dla ludzi, ale nie jest to wymagane.
Jeśli plik zaczął się od różnych bajtów, exec
wywołanie systemowe użyłoby innej procedury obsługi. Innym najważniejszym wbudowanym modułem obsługi są pliki wykonywalne ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305, który sprawdza bajty 7f 45 4c 46
(które również są ludźmi) czytelne dla .ELF
). Potwierdźmy to, czytając 4 pierwsze bajty /bin/ls
, czyli plik wykonywalny ELF:
head -c 4 "$(which ls)" | hd
wynik:
00000000 7f 45 4c 46 |.ELF|
00000004
Więc kiedy jądro zobaczy te bajty, pobiera plik ELF, poprawnie zapisuje go w pamięci i rozpoczyna z nim nowy proces. Zobacz także: W jaki sposób jądro uzyskuje wykonywalny plik binarny działający pod Linuksem?
Na koniec możesz dodać własne binfmt_misc
mechanizmy shebang za pomocą mechanizmu. Na przykład możesz dodać niestandardowy moduł obsługi .jar
plików . Ten mechanizm obsługuje nawet programy obsługi według rozszerzeń plików. Inną aplikacją jest przezroczyste uruchamianie plików wykonywalnych o innej architekturze za pomocą QEMU .
Nie sądzę jednak, że POSIX określa shebangs: https://unix.stackexchange.com/a/346214/32558 , chociaż wspomina o tym w sekcjach uzasadnienia oraz w formie „jeśli skrypty wykonywalne są obsługiwane przez system, coś może zdarzyć". Wydaje się jednak, że macOS i FreeBSD go implementują.
PATH
motywacja do wyszukiwania
Prawdopodobnie jedną z głównych motywów istnienia shebangów jest fakt, że w Linuksie często chcemy uruchamiać polecenia z PATH
:
basename-of-command
zamiast:
/full/path/to/basename-of-command
Ale bez mechanizmu shebang skąd Linux wiedziałby, jak uruchomić każdy typ pliku?
Kodowanie rozszerzenia w poleceniach:
basename-of-command.py
lub wdrożenie wyszukiwania PATH na każdym tłumaczu:
python basename-of-command
byłaby możliwa, ale to ma główny problem, że wszystko się psuje, jeśli kiedykolwiek zdecydujemy się zmienić polecenie na inny język.
Shebangi pięknie rozwiązują ten problem.
Technicznie rzecz biorąc, w Pythonie jest to tylko wiersz komentarza.
Ten wiersz jest używany tylko wtedy, gdy uruchomisz skrypt py z powłoki (z wiersza poleceń). Nazywa się to „ Shebang !” i jest używany w różnych sytuacjach, nie tylko ze skryptami Python.
Tutaj instruuje powłokę, aby uruchomiła określoną wersję Pythona (aby zająć się resztą pliku.
py.exe
. Jest to część standardowej instalacji Pythona.
Głównym powodem tego jest uczynienie skryptu przenośnym w środowiskach systemu operacyjnego.
Na przykład w mingw skrypty python używają:
#!/c/python3k/python
a w dystrybucji GNU / Linux jest to albo:
#!/usr/local/bin/python
lub
#!/usr/bin/python
w ramach najlepszego komercyjnego systemu Uni / SW ze wszystkich (OS / X) jest to:
#!/Applications/MacPython 2.5/python
lub na FreeBSD:
#!/usr/local/bin/python
Jednak wszystkie te różnice mogą sprawić, że skrypt będzie przenośny we wszystkich przy użyciu:
#!/usr/bin/env python
/usr/bin/python
. Pod Linuksem Python zainstalowany przez system jest również prawie na pewno /usr/bin/python
(nigdy nie widziałem nic innego i nie miałoby to sensu). Pamiętaj, że mogą istnieć systemy, które nie mają /usr/bin/env
.
python
nie jest tak przenośny, to domyślny interpreter Pythona w dystrybucji. Arch Linux domyślnie
Prawdopodobnie sensowne jest podkreślenie jednej rzeczy, której większość przeoczyła, co może uniemożliwić natychmiastowe zrozumienie. Kiedy piszeszpython
w terminalu zwykle nie podajesz pełnej ścieżki. Zamiast tego plik wykonywalny jest sprawdzany w PATH
zmiennej środowiskowej. Z kolei, jeśli chcesz bezpośrednio uruchomić program w języku Python /path/to/app.py
, musisz powiedzieć powłoce, jakiego interpretera ma użyć (za pomocą skrótu , co inni współautorzy wyjaśniają powyżej).
Hashbang oczekuje pełnej ścieżki do tłumacza. Aby więc bezpośrednio uruchomić program w języku Python, musisz podać pełną ścieżkę do pliku binarnego w języku Python, który różni się znacznie, szczególnie biorąc pod uwagę użycie virtualenv . Aby rozwiązać problem przenośności, zastosowano sztuczkę /usr/bin/env
. Ten ostatni ma pierwotnie na celu zmianę środowiska w miejscu i uruchomienie w nim polecenia. Jeśli nie wprowadzono żadnych zmian, uruchamia polecenie w bieżącym środowisku, co skutecznie skutkuje tym samym PATH
wyszukiwaniem, które załatwia sprawę .
Jest to konwencja powłoki, która informuje powłokę, który program może wykonać skrypt.
#! / usr / bin / env python
rozwiązuje ścieżkę do pliku binarnego Python.
Jest to zalecany sposób zaproponowany w dokumentacji:
2.2.2 Wykonywalne skrypty Pythona
W systemach BSD'ish Unix, skrypty Pythona mogą być bezpośrednio uruchamiane, podobnie jak skrypty powłoki, poprzez umieszczenie wiersza
#! /usr/bin/env python3.2
z http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Możesz spróbować rozwiązać ten problem, używając virtualenv
Oto test.py
#! /usr/bin/env python
import sys
print(sys.version)
Twórz środowiska wirtualne
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
aktywuj każde środowisko, a następnie sprawdź różnice
echo $PATH
./test.py
Określa tylko jakiego interpretera chcesz użyć. Aby to zrozumieć, utwórz plik przez terminal, wykonując touch test.py
, a następnie wpisz w tym pliku następujące czynności:
#!/usr/bin/env python3
print "test"
i zrobić, chmod +x test.py
aby skrypt był wykonywalny. Po tym ./test.py
powinieneś otrzymać komunikat o błędzie:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
ponieważ python3 nie obsługuje operatora drukowania.
Teraz idź dalej i zmień pierwszą linię kodu na:
#!/usr/bin/env python2
i będzie działać, drukując test
na standardowe wyjście, ponieważ python2 obsługuje operator drukowania. Teraz nauczyłeś się przełączać między interpretatorami skryptów.
Wydaje mi się, że pliki działają tak samo bez tej linii.
Jeśli tak, to może używasz programu Python w systemie Windows? Windows nie używa tej linii - zamiast tego używa rozszerzenia nazwy pliku do uruchomienia programu skojarzonego z tym rozszerzeniem.
Jednak w 2011 r. Opracowano „program uruchamiający w języku Python”, który (do pewnego stopnia) naśladuje zachowanie systemu Linux w systemie Windows. Jest to ograniczone tylko do wyboru, który interpreter Pythona ma być uruchomiony - np. Do wyboru między Pythonem 2 a Pythonem 3 w systemie, w którym oba są zainstalowane. Program uruchamiający jest opcjonalnie instalowany jak py.exe
podczas instalacji w języku Python i może być powiązany z .py
plikami, dzięki czemu program uruchamiający sprawdzi tę linię, a następnie uruchomi określoną wersję interpretera języka Python.
$ python myscript.py
.
Jest to bardziej informacja historyczna niż „prawdziwa” odpowiedź.
Pamiętaj, że w dawnych czasach pan miał wiele systemów operacyjnych UNIX jak projektanci, których wszyscy mieli swoje własne pojęcie gdzie umieścić rzeczy, a czasami nie obejmują Python, Perl, Bash, lub wiele innych GNU / Open Source rzeczy w ogóle .
Dotyczyło to nawet różnych dystrybucji Linuksa. W systemie Linux - wcześniejszym niż FHS [1] - możesz mieć Pythona w / usr / bin / lub / usr / local / bin /. Lub może nie został zainstalowany, więc zbudowałeś swój własny i umieściłeś go w ~ / bin
Solaris był najgorszy, na jakim kiedykolwiek pracowałem, częściowo jako przejście z Berkeley Unix na System V. Możesz skończyć z rzeczami w / usr /, / usr / local /, / usr / ucb, / opt / itp. To może sprawić, że dla niektórych naprawdę długich ścieżek. Mam wspomnienia z Sunfreeware.com instalującego każdy pakiet we własnym katalogu, ale nie mogę sobie przypomnieć, czy to dowiązało pliki binarne do / usr / bin, czy nie.
Aha, a czasami / usr / bin był na serwerze NFS [2].
Więc env
narzędzie zostało opracowane, aby obejść ten problem.
Potem można było pisać #!/bin/env interpreter
i tak długo, jak ścieżka była właściwa, istniała rozsądna szansa na bieg. Oczywiście rozsądne oznaczenie (dla Pythona i Perla), że ustawiłeś także odpowiednie zmienne środowiskowe. W przypadku bash / ksh / zsh to po prostu działało.
Było to ważne, ponieważ ludzie przekazywali skrypty powłoki (takie jak Perl i Python), a jeśli na stałe zapisałeś / usr / bin / python na stacji roboczej Red Hat Linux, zepsuje się na SGI ... no cóż, nie , Myślę, że IRIX umieścił pytona we właściwym miejscu. Ale na stacji Sparc może wcale nie działać.
Tęsknię za moją stacją Sparc. Ale nie za dużo. Ok, teraz masz mnie trollującego po E-Bay. Bastages
[1] Standard hierarchii systemu plików. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Tak, a czasem ludzie nadal robią takie rzeczy. I nie, nie miałem na pasku ani rzepy, ani cebuli.
Jeśli uruchamiasz skrypt w środowisku wirtualnym, powiedzmy venv
, wykonanie go which python
podczas pracy venv
wyświetli ścieżkę do interpretera Pythona:
~/Envs/venv/bin/python
Zauważ, że nazwa środowiska wirtualnego jest osadzona w ścieżce do interpretera Pythona. Dlatego też zakodowanie tej ścieżki w skrypcie spowoduje dwa problemy:
Dlatego, aby dodać odpowiedź Jonathana , idealnym shebang jest #!/usr/bin/env python
nie tylko przenośność w różnych systemach operacyjnych, ale także przenośność w środowiskach wirtualnych!
Biorąc pod uwagę problemy związane z przenośnością między python2
i python3
, zawsze należy określić jedną z wersji, chyba że program jest zgodny z obydwoma.
Niektóre dystrybucje python
wysyłane są python3
przez jakiś czas z linkami - nie polegaj na python
byciu python2
.
Podkreśla to PEP 394 :
Aby tolerować różnice między platformami, cały nowy kod, który musi wywoływać interpreter Pythona, nie powinien określać Pythona, a raczej python2 lub python3 (lub bardziej szczegółowe wersje python2.x i python3.x; zobacz uwagi dotyczące migracji ) . Tego rozróżnienia należy dokonać w shebangach, podczas wywoływania ze skryptu powłoki, podczas wywoływania za pomocą wywołania system () lub przy każdym innym kontekście.
Pozwala wybrać plik wykonywalny, którego chcesz użyć; co jest bardzo przydatne, jeśli być może masz wiele instalacji Pythona i różne moduły w każdym i chcesz wybrać. na przykład
#!/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())
informuje to skrypt, gdzie jest katalog python!
#! /usr/bin/env python
#!/usr/bin/env python
u góry.