Czy jest możliwe, aby shebang, zamiast określać ścieżkę do tłumacza, ma nazwę tłumacza i pozwala powłoce znaleźć go przez $ PATH?
Jeśli nie, czy istnieje powód, dla którego?
Czy jest możliwe, aby shebang, zamiast określać ścieżkę do tłumacza, ma nazwę tłumacza i pozwala powłoce znaleźć go przez $ PATH?
Jeśli nie, czy istnieje powód, dla którego?
Odpowiedzi:
Wyszukiwanie PATH jest cechą standardowej biblioteki C w przestrzeni użytkownika, podobnie jak ogólnie zmienne środowiskowe. Jądro nie widzi zmiennych środowiskowych, z wyjątkiem sytuacji, gdy przechodzi ono przez środowisko wywołujące execve
do nowego procesu.
Jądro nie dokonuje żadnej interpretacji ścieżki w execve
(zależy od funkcji otoki, takich jak execvp
wyszukiwanie PATH) lub w shebang (który mniej więcej przekierowuje execve
wewnętrznie wywołanie). Musisz więc umieścić absolutną ścieżkę w shebang¹. Oryginalna realizacja shebang było tylko kilka linii kodu, a nie został znacząco rozszerzony od.
W pierwszych wersjach Uniksa powłoka wykonała zadanie wywołania się, gdy zauważyła, że wywołujesz skrypt. Shebang został dodany do jądra z kilku powodów (podsumowując uzasadnienie Dennisa Ritchiego :
Bezprzestrzenne shebangs wymagałyby albo rozszerzenia jądra, aby uzyskać dostęp do zmiennych środowiskowych i procesu PATH
, albo też aby jądro wykonało program przestrzeni użytkownika, który wykonuje wyszukiwanie PATH. Pierwsza metoda wymaga dodania nieproporcjonalnej złożoności do jądra. Druga metoda jest już możliwa z #!/usr/bin/env
shebang .
¹ Jeśli umieścisz ścieżkę względną, zostanie ona zinterpretowana w stosunku do bieżącego katalogu procesu (nie katalogu zawierającego skrypt), co jest mało przydatne w shebang.
execve
ani w shebang, chociaż nie ma sensu mieć ścieżki względnej w shebang.
/lib64/ld-linux-x86-64.so.2
(patrz ldd
dane wyjściowe). Linux sprawia, że jest w pełni ogólny: binfmt
obsługa (od 2.1.43) pozwala rejestrować pary interpreter-ścieżka / magiczny numer lub rozszerzenie pliku. Możesz .exe
uruchomić PE32 wine
po uruchomieniu, wywołać klasę Java i pliki jar java
, itp. Itd.
Dzieje się więcej niż na pierwszy rzut oka. #!
linie są interpretowane przez jądro Unixa lub Linuksa, #!
nie jest to aspekt powłoki. Oznacza to, że PATH
tak naprawdę nie istnieje w chwili, gdy jądro decyduje, co wykonać.
Najczęstszym sposobem radzenia sobie z nieświadomością, który plik wykonywalny uruchomić, lub aby zadzwonić perl
w sposób przenośny lub podobny, jest użycie #!/usr/bin/env perl
. Jądro wykonuje się /usr/bin/env
, co dziedziczy PATH
zmienną środowiskową. env
znaleziska (w tym przykładzie) perl
w PATH
i wykorzystuje execve(2)
wywołanie systemowe, aby jądra do uruchomienia perl
pliku wykonywalnego.
$ strace sleep 1
execve("/usr/bin/sleep", ["sleep", "1"], [/* 99 vars */]) = 0
Konwersja do pełnej ścieżki jest wykonywana przez powłokę (bardziej ogólnie: w przestrzeni użytkownika). Jądro oczekuje nazwy pliku / ścieżki, do której może uzyskać bezpośredni dostęp.
Jeśli chcesz, aby system znalazł plik wykonywalny, przeglądając zmienną PATH, możesz przepisać swój shebang jako #!/usr/bin/env EXEC
.
Ale także w tym przypadku wyszukiwanie nie odbywa się przez jądro.
strace
( /usr/bin/strace
w pewnym momencie została przekonwertowana ) z 2 argumentami.