Powinienem wstawić #! (shebang) w skryptach Pythona i jaką formę powinien przyjąć?

828

Czy powinienem umieścić shebang w moich skryptach Python? W jakiej formie

#!/usr/bin/env python 

lub

#!/usr/local/bin/python

Czy są one równie przenośne? Która forma jest najczęściej używana?

Uwaga: tornado projekt wykorzystuje shebang. Z drugiej stronyprojekt Django tego nie robi.

treecoder
źródło
70
Drugi nie jest przenośny i będzie nie na wielu komputerach, jeśli nie większość.
Dietrich Epp
4
Jak wypada #!/usr/bin/pythonporównanie z pierwszą opcją? Widzę to w dość przykładowym kodzie. Edycja: Może to jest odpowiedź .. stackoverflow.com/a/2429517/1156245
geotheory
1
Mówię zawsze, używaj tego, dlaczego? „Zen Of Python” - wiersz 2 - „Jawne jest lepsze niż niejawne”. python.org/dev/peps/pep-0020
JayRizzo
2
Szczerze mówiąc, żadna z nich nie jest „właściwa”, ponieważ jako autor nie wiesz, gdzie będzie poprawna wersja Pythona po uruchomieniu skryptu. To powinno być zadanie dla instalatora , aby dodać prawidłową shebang.
chepner

Odpowiedzi:

1117

Linia shebang w dowolnym skrypcie określa zdolność skryptu do wykonania jak samodzielny plik wykonywalny bez pythonwcześniejszego wpisywania w terminalu lub po dwukrotnym kliknięciu go w menedżerze plików (przy prawidłowej konfiguracji). Nie jest to konieczne, ale zazwyczaj umieszczane tam, więc gdy ktoś zobaczy plik otwarty w edytorze, natychmiast wie, na co patrzy. Ważne jest jednak to, która linia shebang jest używana .

Prawidłowe użycie skryptów Python 3 to:

#!/usr/bin/env python3

Domyślnie jest to wersja 3. najnowsza. Dla Python 2.7. Ostatnie użycie python2zamiast python3.

Poniższe NIE powinno być używane (z wyjątkiem rzadkiego przypadku pisania kodu, który jest zgodny zarówno z Pythonem 2.x, jak i 3.x):

#!/usr/bin/env python

Powodem tych zaleceń, podanych w PEP 394 , jest właśnie topython mogą odnosić się do różnych systemów python2lub python3do różnych systemów. Obecnie dotyczy python2większości dystrybucji, ale w pewnym momencie może się to zmienić.

NIE NALEŻY również używać:

#!/usr/local/bin/python

„Python może być zainstalowany w / usr / bin / python lub / bin / python w takich przypadkach, powyższe #! zakończy się niepowodzeniem.”

- "#! / usr / bin / env python" vs "#! / usr / local / bin / python"

GlassGhost
źródło
4
@EliasVanOotegem Jeśli nie możesz być pewien, że Python zostanie znaleziony, /usr/binto jak możesz być pewien, że envzostanie on znaleziony /usr/bin. Jeśli Python jest zainstalowany w niestandardowym miejscu, prawdopodobnie oznacza to, że Python jest skonfigurowany w niestandardowy sposób i w rezultacie skrypt powinien szybko zawieść. W przeciwieństwie do przyjmowania założeń dotyczących właściwości interpretera języka Python i liczenia na najlepsze.
Wydmy,
65
@Dunes: envbędzie zawsze znaleźć w /usr/bin/, a jej zadaniem jest zlokalizowanie kosze (jak pyton) przy użyciu PATH. Bez względu na to, jak jest zainstalowany Python, jego ścieżka zostanie dodana do tej zmiennej i envznajdzie ją (jeśli nie, Python nie zostanie zainstalowany). To jest praca env, i to jest cały powód, dla którego istnieje. Jest to rzecz, która ostrzega środowisko (konfiguruje zmienne env, w tym ścieżki instalacji i zawiera ścieżki). Ludzie zawsze rozumieli, że to polecenie może działać tylko wtedy, gdy zawsze znajduje się w tym samym miejscu. To tylko dane
Elias Van Ootegem,
3
@JFSebastian: Masz rację, nie jest to gwarantowane ani egzekwowane przez standard POSIX. Zakładałem, że było tak, ponieważ jedna z późniejszych wersji IEEE zawierała pewne elementy środowiska. Tak czy inaczej: nie, /usr/bin/envnie jest gwarantowane przez żaden inny standard niż powszechnie przyjęta (powszechnie?) Reguła ...
Elias Van Ootegem,
6
Jeśli używasz virtualenv, #! / Usr / local / bin / python, nawet jeśli istnieje, działa nieprawidłowo.
nullas,
6
Jeden problem z tym: zgodnie z PEP394python plik wykonywalny powinien być używany tylko wtedy, gdy skrypt jest zgodny z Python 2 i Python 3. W przeciwnym razie powinien wskazywać odpowiedni wybór z python2i python3.
amiller27
67

To naprawdę tylko kwestia gustu. Dodanie shebang oznacza, że ​​ludzie mogą bezpośrednio wywoływać skrypt, jeśli chcą (zakładając, że jest oznaczony jako wykonywalny); pominięcie tego oznacza po prostu, że pythonnależy wywoływać ręcznie.

Na wynik końcowy uruchomienia programu nie ma to wpływu; to tylko opcje środków.

Bursztyn
źródło
3
Tylko tyle - nie ma znaczenia, którą stronę podejmiesz, ponieważ nie ma „właściwej” strony. To całkowicie subiektywna decyzja.
Amber
5
Nie więcej niż jakakolwiek inna trywialna decyzja. en.wikipedia.org/wiki/Parkinson's_Law_of_Triviality
Amber
2
Jak mogę wykonać plik python bezpośrednio bez polecenia „python”?
Zen,
5
@Zen Zakładając, że umieściłeś shebang (#! / Usr / bin / env python) w swoim skrypcie, po prostu potrzebujesz, aby skrypt był wykonywalny. Coś takiego chmod a+x [your-script].pypowinno sprawić, że będzie on wykonywalny, a następnie można po prostu wywołać ./[your-script.py]w powłoce.
skålfyfan
9
Jak wskazuje odpowiedź GlassGhost, oprócz gustu jest konkretna zaleta: dla przyszłego czytelnika pliku wyjaśnia, że ​​czyta skrypt wykonywalny, a nie plik przeznaczony do zaimportowania. Podobnie jak w przypadku publicznych / prywatnych modyfikatorów kontroli dostępu w językach, które je mają, shebangi są przydatne jako dokumentacja, a także ze względu na ich rzeczywisty efekt, aw niektórych przypadkach aspekt dokumentacji ma największe znaczenie.
Mark Amery
32

Czy powinienem umieścić shebang w moich skryptach Python?

Umieść shebang w skrypcie Python, aby wskazać:

  • moduł ten można uruchomić jako skrypt
  • czy można go uruchomić tylko na Python2, Python3, czy jest kompatybilny z Python 2/3
  • w POSIX jest konieczne, jeśli chcesz uruchomić skrypt bezpośrednio, bez pythonjawnego wywoływania pliku wykonywalnego

Czy są one równie przenośne? Która forma jest najczęściej używana?

Jeśli piszesz shebang ręcznie, zawsze używaj go, #!/usr/bin/env pythonchyba że masz konkretny powód, aby go nie używać. Ten formularz jest zrozumiały nawet w systemie Windows (program uruchamiający w języku Python).

Uwaga: zainstalowane skrypty powinny używać określonego pliku wykonywalnego Pythona, np . /usr/bin/pythonLub /home/me/.virtualenvs/project/bin/python. Źle, jeśli jakieś narzędzie się zepsuje, jeśli aktywujesz virtualenv w swojej powłoce. Na szczęście poprawny shebang jest tworzony automatycznie w większości przypadków przez setuptoolsnarzędzia pakietu dystrybucyjnego (w systemie Windows setuptoolsmożna wygenerować opakowanie).exe automatycznie skrypty ).

Innymi słowy, jeśli skrypt znajduje się w kasie źródłowej, prawdopodobnie zobaczysz #!/usr/bin/env python. Jeśli jest zainstalowany, shebang jest ścieżką do określonego pliku wykonywalnego Pythona, takiego jak#!/usr/local/bin/python (UWAGA: nie należy ręcznie pisać ścieżek z tej drugiej kategorii).

Aby wybrać, czy chcesz używać python, python2czy python3w trybie shebang, zobacz PEP 394 - Polecenie „python” w systemach uniksopodobnych :

  • ... pythonnależy używać w wierszu shebang tylko w przypadku skryptów zgodnych ze źródłami zarówno dla Pythona 2, jak i 3.

  • w ramach przygotowań do ewentualnej zmiany domyślnej wersji języka Python, skrypty tylko w języku Python 2 powinny zostać zaktualizowane, aby były zgodne ze źródłami języka Python 3, lub też python2w linii shebang.

jfs
źródło
3
Pierwsza odpowiedź odnosząca się nawet do PEP nie ma wystarczającej liczby głosów pozytywnych. Co? Czy istnieje PEP dla #!/usr/bin/env pythonsiebie?
binki
Proszę nie używać #!/usr/bin/env python. Nie sugeruj „zawsze używaj” #!/usr/bin/env python. Jest to niewłaściwe postępowanie w 99% przypadków (powód, który podałeś w odpowiedzi).
Jay Sullivan
1
@JaySullivan, czy rozumiesz różnicę między kasą źródłową a zainstalowanymi skryptami? Popieram sugestię. To dobrze działa.
jfs
1
@jfs: Po ponownym przeczytaniu mojego komentarza widzę, jak całkowicie nie udało mi się przekonać. Miałem na myśli to, że większość ludzi będzie chciała używać „python2” lub „python3”, a nie „python”. Niezależnie od tego, czy rozwiązać za pomocą pełnej ścieżki lub env, które technicznie było pytaniem OP, odpowiedziałeś i nie zgadzam się w tej kwestii.
Jay Sullivan
@JaySullivan Zgadzam się. Czy przeczytałeś cytat z odpowiedzi w odpowiedzi? Mówi to samo.
jfs
15

Jeśli masz więcej niż jedną wersję Pythona, a skrypt musi działać pod określoną wersją, she-bang może zapewnić, że odpowiedni jest używany, gdy skrypt jest wykonywany bezpośrednio, na przykład:

#!/usr/bin/python2.7

Uwaga: skrypt nadal może być uruchamiany za pomocą pełnego wiersza polecenia Python lub importu, w którym to przypadku she-bang jest ignorowana. Ale w przypadku skryptów uruchamianych bezpośrednio jest to dobry powód, aby używać she-bang.

#!/usr/bin/env python jest ogólnie lepszym podejściem, ale pomaga to w szczególnych przypadkach.

Zwykle lepiej byłoby ustanowić wirtualne środowisko Python, w którym to przypadku rodzajowa #!/usr/bin/env pythonzidentyfikowałaby poprawną instancję Pythona dla virtualenv.

Chris Johnson
źródło
Czy przestrzeń nie spowoduje awarii?
RandomInsano
1
@RandomInsano, nie sądzę. Spacje wydają się dość powszechne, a wokół sieci jest wiele dowodów na to, że jest to zaakceptowane użycie. Myślę jednak, że brak przestrzeni jest prawdopodobnie bardziej kanonicznym zastosowaniem.
Chris Johnson
1
Zdecydowanie masz rację w tej sprawie. Właśnie przetestowane na bash i tcsh.
RandomInsano
Wyniki whichda ci ciąg, który będzie działać, kropka. Nie musisz się martwić o odwagę, aby z niej skorzystać.
SDsolar
10

Powinieneś dodać shebang, jeśli skrypt ma być wykonywalny. Powinieneś także zainstalować skrypt z oprogramowaniem instalacyjnym, które modyfikuje shebang do czegoś poprawnego, aby działał na platformie docelowej. Przykładami tego są distutils i Distribution.

Lennart Regebro
źródło
1
Nie musisz modyfikować #! linia później. Do tego służy / usr / bin / env. Kodowanie na konkretny interpreter języka Python może wyrządzić więcej szkody niż pożytku. Jest bardzo delikatny w kwestii instalowania innej wersji Pythona lub przełączania między Pythonem naszej dystrybucji a niestandardową instalacją Pythona.
vog
W Ubuntu użycie wyników whichautomatycznie wybierze wartość domyślną używaną przez polecenia systemowe i tym podobne. Jest ogólny, a system steruje nim do właściwej instalacji.
SDsolar
9

Funkcja shebang ma na celu rozpoznanie przez skrypt typu interpretera, gdy skrypt ma zostać wykonany z powłoki. Przeważnie i nie zawsze wykonujesz skrypty, dostarczając interpretera na zewnątrz. Przykładowe użycie:python-x.x script.py

To zadziała, nawet jeśli nie masz deklaratora shebang.

Dlaczego pierwszy jest bardziej „przenośny”, ponieważ /usr/bin/envzawiera twójPATH deklarację, która uwzględnia wszystkie miejsca docelowe, w których znajdują się pliki wykonywalne systemu.

UWAGA: Tornado nie stosuje wyłącznie shebangów, a Django nie. Różni się w zależności od sposobu wykonywania głównej funkcji aplikacji.

RÓWNIEŻ: Nie zmienia się w Pythonie.

meson10
źródło
8

Czasami, jeśli odpowiedź nie jest bardzo jasna (to znaczy nie możesz zdecydować, czy tak, czy nie), to nie ma to większego znaczenia i możesz zignorować problem, dopóki odpowiedź nie będzie jasna.

#!Jedynym celem jest uruchomienie skryptu. Django ładuje źródła samodzielnie i używa ich. Nigdy nie musi decydować, jakiego tłumacza należy użyć. W ten sposób #!nie ma tu sensu.

Zasadniczo, jeśli jest to moduł i nie można go użyć jako skryptu, nie ma potrzeby używania #!. Z drugiej strony źródło modułu często zawiera if __name__ == '__main__': ...przynajmniej trywialne testy funkcjonalności. To znów #!ma sens.

Jednym z dobrych powodów #!jest użycie zarówno skryptów Python 2, jak i Python 3 - muszą one być interpretowane przez różne wersje Pythona. W ten sposób musisz pamiętać, z czego pythonnależy korzystać podczas ręcznego uruchamiania skryptu (bez jego #!wnętrza). Jeśli masz wiele takich skryptów, dobrym pomysłem jest skorzystanie z ich #!wnętrza, uczynienie ich wykonywalnymi i uruchomienie ich jako plików wykonywalnych (chmod ...).

Podczas korzystania z MS-Windows #!nie miało to sensu - do niedawna. Python 3.3 wprowadza Windows Python Launcher (py.exe i pyw.exe), który odczytuje #!wiersz, wykrywa zainstalowane wersje Pythona i używa poprawnej lub wyraźnie pożądanej wersji Pythona. Ponieważ rozszerzenie może być powiązane z programem, możesz uzyskać podobne zachowanie w systemie Windows, jak w przypadku flagi wykonania w systemach uniksowych.

pepr
źródło
3

Kiedy ostatnio zainstalowałem Python 3.6.1 na Windows 7, zainstalowałem także Python Launcher dla Windows, który powinien obsługiwać linię shebang. Odkryłem jednak, że Launcher Python tego nie zrobił: linia shebang została zignorowana, a Python 2.7.13 był zawsze używany (chyba że wykonałem skrypt za pomocą py -3).

Aby to naprawić, musiałem edytować klucz rejestru systemu Windows HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Python.File\shell\open\command. To wciąż miało wartość

"C:\Python27\python.exe" "%1" %*

z mojej wcześniejszej instalacji Python 2.7. Zmodyfikowałem tę wartość klucza rejestru na

"C:\Windows\py.exe" "%1" %*

a przetwarzanie linii shebang w Python Launcher działało jak opisano powyżej.

ETalbot
źródło
2

Jeśli masz zainstalowane różne moduły i musisz użyć konkretnej instalacji Pythona, wtedy shebang wydaje się początkowo ograniczony. Możesz jednak wykonać takie sztuczki, jak poniżej, aby najpierw wywołać szewang jako skrypt powłoki, a następnie wybrać python. To jest bardzo elastyczne imo:

#!/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 $PREFERRED_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())

A może jeszcze lepiej, aby ułatwić ponowne użycie kodu w wielu skryptach Pythona:

#!/bin/bash
"true" '''\'; source $(cd $(dirname ${BASH_SOURCE[@]}) &>/dev/null && pwd)/select.sh; exec $CHOSEN_PYTHON "$0" "$@"; exit 127; '''

a następnie select.sh ma:

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
    CHOSEN_PYTHON=$PREFERRED_PYTHON
elif [ -x $ALTERNATIVE_PYTHON ]; then
    CHOSEN_PYTHON=$ALTERNATIVE_PYTHON
else
    CHOSEN_PYTHON=$FALLBACK_PYTHON
fi
Neil McGill
źródło
1
Chociaż nie jestem pewien, czy taki poliglot jest ogólnie dobrą praktyką, z pewnością jest to bardzo interesujące podejście i prawdopodobnie najbardziej elastyczna odpowiedź tutaj.
Ryan Amos
1
Bardzo fajny. Nie wiedziałem, że możesz to zrobić
2233949,
1

Odpowiedź: Tylko jeśli planujesz uczynić go skryptem wykonywalnym z linii poleceń.

Oto procedura:

Zacznij od sprawdzenia poprawności łańcucha shebang, którego chcesz użyć:

which python

Weź z tego wynik i dodaj go (z shebang #!) W pierwszym wierszu.

W moim systemie odpowiada tak:

$which python
/usr/bin/python

Twój shebang będzie wyglądał następująco:

#!/usr/bin/python

Po zapisaniu nadal będzie działał jak poprzednio, ponieważ python zobaczy pierwszy wiersz jako komentarz.

python filename.py

Aby ustawić polecenie, skopiuj je, aby upuścić rozszerzenie .py.

cp filename.py filename

Poinformuj system plików, że będzie to możliwe do wykonania:

chmod +x filename

Aby to przetestować, użyj:

./filename

Najlepszą praktyką jest przeniesienie go gdzieś w $ PATH, więc wystarczy wpisać nazwę pliku.

sudo cp filename /usr/sbin

W ten sposób będzie działać wszędzie (bez ./ przed nazwą pliku)

SDsolar
źródło
Wątpię, aby to była najlepsza praktyka i zdecydowanie polecam korzystanie z rozwiązania GlassGhost .
colidyre
Uważam to za pomocne i działało dla mnie pięknie. zostało to dobrze wyjaśnione. Byłbym wdzięczny za komentarze wskazujące, dlaczego nie jest to najlepsza praktyka. Jestem chętny do nauki.
Charles Carriere
0

Ścieżka absolutna vs logiczna:

To jest naprawdę pytanie o to, czy ścieżka do interpretera Pythona powinna być bezwzględna, czy logiczna ( /usr/bin/env) w odniesieniu do przenośności.

Napotykając inne odpowiedzi na tej i innych stronach stosu, które mówiły o tym problemie w sposób ogólny, bez poparcia dowodów, przeprowadziłem naprawdę, NAPRAWDĘ , szczegółowe testy i analizy tego właśnie pytania na unix.stackexchange.com . Zamiast wkleić tę odpowiedź tutaj, skieruję osoby zainteresowane analizą porównawczą do tej odpowiedzi:

https://unix.stackexchange.com/a/566019/334294

Będąc inżynierem systemu Linux, moim celem jest zawsze zapewnienie najbardziej odpowiednich, zoptymalizowanych hostów dla moich klientów programistów, więc kwestia środowisk Python była czymś, na co naprawdę potrzebowałem solidnej odpowiedzi. Mój pogląd po testach był taki, że logiczna ścieżka w She-Bang była lepsza z (2) opcji.

F1Linux
źródło
-3

Użyj najpierw

which python

To da wynik jako lokalizację, w której obecny jest mój interpreter Pythona (binarny).

Ten wynik może być dowolny, na przykład

/usr/bin/python

lub

/bin/python

Teraz odpowiednio wybierz linię shebang i użyj jej.

Do uogólnienia możemy użyć:

#!/usr/bin/env

lub

#!/bin/env
frp farhan
źródło
3
Najprawdopodobniej nie będzie to przenośne na inne systemy. #!/usr/bin/envdokonuje właściwego wyboru dla Ciebie.
fragmentedreality
Dlatego używasz which polecenia - zwróci prawidłowy ciąg znaków dla twojego konkretnego systemu.
SDsolar
1
... a następnie za każdym razem, gdy skrypt ma być wykonywany na innym komputerze, uruchamiasz go which pythonponownie i zmieniasz skrypt, jeśli wynik różni się od bieżącego shebang
fragmentedreality
2
-1 To jest najbardziej kruche możliwe rozwiązanie. Gwarantuje to, że jest poprawna tylko dla systemu, w którym napisany jest skrypt Pythona. Użyj #! / Usr / bin / env python3 dla przenośności
Myles Hollowed