Jeśli skrypty powłoki zaczynają się od #!/bin/bash, zawsze będą działać bashod /bin. Jeśli jednak zaczną od #!/usr/bin/env bash, będą wyszukiwać bashw, $PATHa następnie zaczną od pierwszego, jaki znajdą.
Dlaczego miałoby to być przydatne? Załóżmy, że chcesz uruchamiać bashskrypty, które wymagają wersji bash 4.x lub nowszej, ale twój system ma tylko bashzainstalowaną wersję 3.x, a obecnie twoja dystrybucja nie oferuje nowszej wersji lub nie jesteś administratorem i nie możesz zmienić tego, co jest zainstalowane w tym systemie .
Oczywiście możesz pobrać kod źródłowy bash i zbudować własny bash od zera, umieszczając go ~/binna przykład. Możesz także zmodyfikować $PATHzmienną w swoim .bash_profilepliku, aby uwzględnić ją ~/binjako pierwszy wpis ( PATH=$HOME/bin:$PATHponieważ ~nie będzie się rozwijał $PATH). Jeśli teraz zadzwonisz bash, powłoka najpierw poszuka go $PATHw kolejności, więc zaczyna się od miejsca ~/bin, w którym znajdzie twój bash. To samo dzieje się, jeśli skrypty szukają bashużycia #!/usr/bin/env bash, więc te skrypty będą teraz działać w systemie przy użyciu niestandardowej bashkompilacji.
Jednym minusem jest to, że może to prowadzić do nieoczekiwanego zachowania, np. Ten sam skrypt na tej samej maszynie może działać z różnymi interpretatorami dla różnych środowisk lub użytkowników z różnymi ścieżkami wyszukiwania, powodując różnego rodzaju bóle głowy.
Największym minusem envjest to, że niektóre systemy zezwalają tylko na jeden argument, więc nie można tego zrobić #!/usr/bin/env <interpreter> <arg>, ponieważ systemy będą postrzegane <interpreter> <arg>jako jeden argument (będą traktować to tak, jakby wyrażenie było cytowane), a zatem envbędą szukać tłumacza o nazwie <interpreter> <arg>. Zauważ, że nie jest to problem envsamej komendy, która zawsze pozwalała na przesłanie wielu parametrów, ale z parserem shebang systemu, który analizuje tę linię przed nawet wywołaniem env. Tymczasem zostało to naprawione w większości systemów, ale jeśli twój skrypt chce być bardzo przenośny, nie możesz polegać na tym, że zostało to naprawione w systemie, w którym będziesz działał.
Może nawet mieć wpływ na bezpieczeństwo, np. Jeśli sudonie został skonfigurowany do czyszczenia środowiska lub $PATHzostał wykluczony z czyszczenia. Pokażę to:
Zazwyczaj /binjest to dobrze chronione miejsce, tylko roottam może coś zmienić. Twój katalog domowy nie jest jednak w żadnym programie, który uruchamiasz, może wprowadzać w nim zmiany. Oznacza to, że złośliwy kod może umieścić fałszywy bashw jakimś ukrytym katalogu, zmodyfikować go tak, .bash_profileaby zawierał ten katalog w twoim $PATH, aby wszystkie używane skrypty #!/usr/bin/env bashdziałały z tym fałszywym bash. Jeśli sudotak się stanie $PATH, masz duże kłopoty.
Np. Rozważ narzędzie, które tworzy plik ~/.evil/basho następującej treści:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Stwórzmy prosty skrypt sample.sh:
#!/usr/bin/env bash
echo "Hello World"
Dowód koncepcji (w systemie, w którym sudozachowuje $PATH):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
Zwykle wszystkie powłoki powinny znajdować się w /binśrodku, a jeśli nie chcesz ich tam umieszczać z jakiegokolwiek powodu, naprawdę nie jest problemem umieszczanie dowiązania symbolicznego w /bintych punktach do ich prawdziwych lokalizacji (a może /binsam jest dowiązaniem symbolicznym), więc Zawsze chodziłbym z #!/bin/shi #!/bin/bash. Jest zbyt wiele, co by się zepsuło, gdyby te nie działały. To nie jest tak, że POSIX wymagałby takiej pozycji (POSIX nie standaryzuje nazw ścieżek, a tym samym wcale nie standaryzuje funkcji shebang), ale są one tak powszechne, że nawet jeśli system nie oferowałby /bin/sh, prawdopodobnie by to zrozumiał #!/bin/shi wiedzieć, co z tym zrobić i może to być tylko dla zgodności z istniejącym kodem.
Ale w przypadku bardziej nowoczesnych, niestandardowych, opcjonalnych interpreterów, takich jak Perl, PHP, Python lub Ruby, nie jest tak naprawdę nigdzie określone, gdzie powinny się znajdować. Mogą być /usr/bin, ale mogą także znajdować się w /usr/local/binlub w zupełnie innej branży (hierarchii /opt/..., /Applications/...itp). Dlatego często używają #!/usr/bin/env xxxskładni shebang.