W nagłówku skryptu Bash jaka jest różnica między tymi dwiema instrukcjami:
#!/usr/bin/env bash
#!/usr/bin/bash
Kiedy przejrzałem env
stronę podręcznika , otrzymałem następującą definicję:
env - run a program in a modified environment
Co to znaczy?
Odpowiedzi:
Uruchamianie pomocy komendy
/usr/bin/env
ma korzyść szuka cokolwiek domyślna wersja programu jest w aktualnej env ironment.W ten sposób nie musisz szukać go w określonym miejscu w systemie, ponieważ ścieżki te mogą znajdować się w różnych lokalizacjach w różnych systemach. Tak długo, jak będzie na twojej ścieżce, będzie ją znajdować.
Jednym minusem jest to, że nie będziesz w stanie przekazać więcej niż jednego argumentu (np. Nie będziesz mógł pisać
/usr/bin/env awk -f
), jeśli chcesz obsługiwać Linuksa, ponieważ POSIX jest niejasny w kwestii interpretacji linii, a Linux interpretuje wszystko po pierwszym spacja oznaczająca pojedynczy argument. Możesz użyć/usr/bin/env -S
niektórych wersji,env
aby obejść ten problem, ale wtedy skrypt stanie się jeszcze mniej przenośny i zepsuje się na dość niedawnych systemach (np. Nawet Ubuntu 16.04, jeśli nie później).Inną wadą jest to, że ponieważ nie wywołujesz jawnego pliku wykonywalnego, może to powodować błędy, a także problemy z bezpieczeństwem systemów wielu użytkowników (na przykład, jeśli ktoś zdoła wywołać plik wykonywalny
bash
na twojej ścieżce).W niektórych sytuacjach pierwsza może być preferowana (np. Uruchamianie skryptów Pythona z wieloma wersjami Pythona, bez konieczności przerabiania wiersza wykonywalnego). Ale w sytuacjach, w których najważniejsze jest bezpieczeństwo, to drugie byłoby preferowane, ponieważ ogranicza możliwości wstrzykiwania kodu.
źródło
#!/usr/bin/env echo Hello
narzeka:/usr/bin/env: echo Hello: No such file or directory
. Najwyraźniej traktuje toecho Hello
jako pojedynczy argument przeciwko/usr/bin/env
.env
Polecenie z pewnością pozwala na przekazanie argumentów do polecenia. Problemem jest semantyka#!
linii, która zależy od jądra. Najnowsze jądra Linuksa pozwalają na takie rzeczy#!/usr/bin/env command args
, ale starsze jądra Linuksa i inne systemy nie.Użycie
#!/usr/bin/env NAME
powoduje, że powłoka szuka pierwszego dopasowania NAME w zmiennej środowiskowej $ PATH. Może być przydatny, jeśli nie znasz ścieżki bezwzględnej lub nie chcesz jej szukać.źródło
Zamiast jawnego zdefiniowania ścieżki do interpretera za
/usr/bin/bash/
pomocą polecenia env, interpreter jest wyszukiwany i uruchamiany z dowolnego miejsca, w którym został znaleziony. Ma to zarówno zalety, jak i wadyźródło
Jeśli skrypty powłoki zaczynają się od
#!/bin/bash
, zawsze będą działaćbash
od/bin
. Jeśli jednak zaczną od#!/usr/bin/env bash
, będą wyszukiwaćbash
w,$PATH
a następnie zaczną od pierwszego, jaki znajdą.Dlaczego miałoby to być przydatne? Załóżmy, że chcesz uruchamiać
bash
skrypty, które wymagają wersji bash 4.x lub nowszej, ale twój system ma tylkobash
zainstalowaną 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
~/bin
na przykład. Możesz także zmodyfikować$PATH
zmienną w swoim.bash_profile
pliku, aby uwzględnić ją~/bin
jako pierwszy wpis (PATH=$HOME/bin:$PATH
ponieważ~
nie będzie się rozwijał$PATH
). Jeśli teraz zadzwoniszbash
, powłoka najpierw poszuka go$PATH
w kolejności, więc zaczyna się od miejsca~/bin
, w którym znajdzie twójbash
. To samo dzieje się, jeśli skrypty szukająbash
użycia#!/usr/bin/env bash
, więc te skrypty będą teraz działać w systemie przy użyciu niestandardowejbash
kompilacji.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
env
jest 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 zatemenv
będą szukać tłumacza o nazwie<interpreter> <arg>
. Zauważ, że nie jest to problemenv
samej 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łaniemenv
. 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
sudo
nie został skonfigurowany do czyszczenia środowiska lub$PATH
został wykluczony z czyszczenia. Pokażę to:Zazwyczaj
/bin
jest to dobrze chronione miejsce, tylkoroot
tam 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łszywybash
w jakimś ukrytym katalogu, zmodyfikować go tak,.bash_profile
aby zawierał ten katalog w twoim$PATH
, aby wszystkie używane skrypty#!/usr/bin/env bash
działały z tym fałszywymbash
. Jeślisudo
tak się stanie$PATH
, masz duże kłopoty.Np. Rozważ narzędzie, które tworzy plik
~/.evil/bash
o następującej treści:Stwórzmy prosty skrypt
sample.sh
:Dowód koncepcji (w systemie, w którym
sudo
zachowuje$PATH
):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/bin
tych punktach do ich prawdziwych lokalizacji (a może/bin
sam jest dowiązaniem symbolicznym), więc Zawsze chodziłbym z#!/bin/sh
i#!/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/sh
i 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/bin
lub w zupełnie innej branży (hierarchii/opt/...
,/Applications/...
itp). Dlatego często używają#!/usr/bin/env xxx
składni shebang.źródło
Uważam to za przydatne, ponieważ kiedy nie wiedziałem o env, zanim zacząłem pisać skrypt, robiłem to:
a potem modyfikowałem tę linię w pliku do shebang.
Robiłem to, ponieważ nie zawsze pamiętałem, gdzie jest nodejs na moim komputerze - / usr / bin / lub / bin /, więc dla mnie
env
jest bardzo przydatny. Może są w tym szczegóły, ale to jest mój powódźródło