Skąd / usr / bin / env wie, którego programu użyć?

62

Kiedy używam shebang #!/usr/bin/env pythondo uruchamiania skryptu, skąd system wie, którego pythonużyć? jeśli szukam pythonścieżki bin w zmiennych środowiskowych, nic nie znajduję.

env | grep -i python
tMC
źródło
6
och, myślę, że wymyśliłem to - po prostu wyszukuje twoją $ PATH pod kątem „python”
tMC
Też się nad tym zastanawiałem. A dlaczego / usr / bin / env? w przeciwieństwie do / bin / env lub env, jeśli tylko pobiera listę ścieżek z env?
Faheem Mitha
Po prostu „env” nie będzie działać, ponieważ musi to być pełna ścieżka. Program „env” zwykle znajduje się w / user / bin / env. W niektórych dystrybucjach można go również znaleźć jako / bin / env, ale bezpieczniej jest używać / usr / bin / env.
Rettops

Odpowiedzi:

54

Shebang oczekuje użycia pełnej ścieżki do interpretera, więc następująca składnia byłaby niepoprawna:

#!python

Ustawienie pełnej ścieżki w ten sposób może działać:

#!/usr/local/bin/python

ale byłoby non przenośny jak pyton mogą być instalowane w /bin, /opt/python/binlub gdziekolwiek inną lokalizację.

Za pomocą env

#!/usr/bin/env python

jest metodą pozwalającą przenośnemu sposobowi na określenie w systemie operacyjnym pełnej ścieżki równoważnej ścieżce, w której pythonnajpierw znajduje się on w systemie PATH.

jlliagre
źródło
56

Linia shebang (z „ostrego huku”, tj. #!) Jest przetwarzana przez jądro. Jądro nie chce wiedzieć o zmiennych środowiskowych, takich jak PATH. Zatem nazwa w linii shebang musi być bezwzględną ścieżką do pliku wykonywalnego. Możesz także podać dodatkowy argument, który zostanie przekazany do tego pliku wykonywalnego przed nazwą skryptu (z ograniczeniami zależnymi od systemu, nie wchodzę tutaj). Na przykład w przypadku skryptu w języku Python można określić

#!/usr/bin/python

w pierwszym wierszu i po uruchomieniu skryptu jądro faktycznie się uruchomi /usr/bin/python /path/to/script. Ale to nie jest wygodne: musisz podać pełną ścieżkę polecenia. Co jeśli pythonw /usr/binniektórych maszynach i /usr/local/binna innych? Czy chcesz, aby ustawić PATHsię /home/joe/opt/python-2.5/bintak, aby użyć określonej wersji Pythona? Ponieważ jądro nie PATHwyszukuje za ciebie, chodzi o to, aby jądro uruchomiło polecenie, które z kolei szuka żądanego interpretera w PATH:

#!/fixed/path/to/path-lookup-command python

To path-lookup-commandmusi przyjąć nazwę pliku wykonywalnego jako argument, wyszukać go PATHi wykonać: jądro będzie działać /fixed/path/to/path-lookup-command python /path/to/script. Tak się składa, że envpolecenie właśnie to robi. Jego głównym celem jest uruchomienie komendy w innym środowisku, ale ponieważ szuka ona nazwy komendy $PATH, jest idealna do naszego celu tutaj.

Chociaż nie jest to oficjalnie zagwarantować, historyczne systemy Unix przewidziane envw /usr/binoraz nowoczesne systemy zachowali tę lokalizację właśnie ze względu na powszechne stosowanie #!/usr/bin/env. Tak więc w praktyce można określić, że skrypt musi zostać wykonany przez ulubionego interpretera języka Python

#!/usr/bin/env python
Gilles
źródło
2
który jest preferowany pomiędzy enva which? od którego otrzymam również najbardziej odpowiedni plik wykonywalny z mojego środowiska PATH.
Nikhil Mulley
8
@NikhilMulley whichznajduje plik wykonywalny i drukuje jego ścieżkę. envznajduje program określony przez pierwszy argument i wykonuje go, przekazując mu pozostałe argumenty.
Kevin
3
więc jest to envwersja ewaluacyjna which.
Nikhil Mulley
6

Racja, więc uruchom:

env | grep PATH

Twoja $ PATH to lista katalogów. Unix będzie przeglądał tę listę katalogów w kolejności, aż znajdzie „python”.

Możesz sprawdzić, który katalog znajduje, za pomocą polecenia „which”:

which python
Dan Rue
źródło
Co ciekawe, widzę różnicę w pythonie sys.pathmiędzy aktywowaną env $ env python3 ( ['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']) i ./env/bin/python3 (['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/test/env3/lib/python3.4/site-packages']).
ThorSummoner,