Użyj #! / Bin / sh lub #! / Bin / bash dla kompatybilności z Ubuntu-OSX oraz łatwości użytkowania i POSIX

18

Wiem, że mogę użyć jednego z pierwszych wierszy skryptów do wywołania pożądanej powłoki.

Byłoby #!/bin/shzalecane, jeśli zgodność ze wszystkimi systemami uniksowymi jest absolutnym wymogiem?

W moim przypadku jedynym systemem, na którym mi zależy, jest Ubuntu (Debian) i OSX. Biorąc to pod uwagę, czy mogę używać #!/bin/bashi mieć pewność, że będzie działał na obu systemach?
Czy ułatwiłoby to również korzystanie ze skryptów z bardziej nowoczesną i bardziej przejrzystą składnią poleceń? Czy używanie #!/bin/shodnosi się również do używania POSIX?

Michael Durrant
źródło
1
Prawdopodobnie warto zauważyć, że wiele dystrybucji zaczęło się łączyć /bini /usr/bin. W związku z tym prawdopodobnie lepiej jest teraz używać #!/usr/bin/env <shname>do przenoszenia.
HalosGhost

Odpowiedzi:

15

Na początek, jeśli możesz założyć, że Bash jest wstępnie zainstalowany (co, zgodnie z moją wiedzą, dotyczy wszystkich wymienionych systemów), użyj następującego hashbangu, aby być kompatybilnym:

#!/usr/bin/env bash

wywołuje to wszystko bash, co dzieje się w konfiguracji, bez względu na to, czy jest w, /binczy w /usr/local/bin.

Podczas gdy na większości systemów w szerokim zakresie (w tym AIX, Solaris, kilka odmian BSD), bashtrafiał do różnych lokalizacji, envzawsze trafiał do /usr/bin/env. Sztuczka nie jest jednak moja, ale autorstwa autora książki kucharskiej Bash.

W każdym razie, tak, Bash pozwoliłby ci użyć niektórych „nowoczesnych” funkcji, które ułatwią ci życie.

Na przykład podwójne nawiasy kwadratowe:

[[ -f "/etc/debian_version" ]] && echo "This is a Debian flavor"

mając na uwadze, że w tradycyjnych dialektach skorupowych trzeba by uciekać się do:

test -f "/etc/debian_version" && echo "This is a Debian flavor"

ale najlepsze w podwójnych nawiasach jest to, że pozwalają na dopasowanie wyrażeń regularnych. Bash Hakerzy Wiki daje wiele sztuczek w tym kierunku.

Możesz także użyć całkiem wygodnych wyrażeń, takich jak $((2**10))lub inne wyrażenia arytmetyczne zgodne ze $((expression))składnią.

Używanie backsicków do podpowłok jest w porządku, choć nieco przestarzałe. Ale możliwości zagnieżdżania $(command ...)wywołań są znacznie wygodniejsze, ponieważ nie będziesz musiał uciekać przed wieloma rzeczami na różnych poziomach podpowłoki.

To tylko kilka rzeczy, które oferuje Bash w stosunku do tradycyjnej shskładni POSIX .

Ale jeśli chcesz więcej mocy na powłoce (nie tylko w skryptach), spójrz także zsh.

0xC0000022L
źródło
Bash jest bardzo przydatnym narzędziem, ale uważaj, aby nie używać go do uruchamiania usług, które mogą być podatne na błąd skryptowy Bash, np . Access.redhat.com/security/cve/CVE-2014-6271 . Trzymaj się shtakich zadań.
Rick-777
1
Rick-777, że podatność została znacznie przesadzona i moim zdaniem twój komentarz to FUD. Jeśli usługa systemowa działa w trybie bash, nie jest w żaden sposób podatna na ten błąd. Jest podatny na ten błąd tylko wtedy, gdy odrzuci proces bash, umożliwiając zdalnym użytkownikom bezpośredni dostęp do jednej lub więcej zmiennych środowiskowych, takich jak FastCGI, a nawet wtedy tylko w niepoprawnych wersjach bash. W systemach shpołączonych z bashtą luką luka nie zostanie zmniejszona za pomocą sh.
Score_Under
11

W Debianie i Ubuntu, /bin/shis dash, który jest powłoką zgodną z POSIX. Jeśli określisz #!/bin/sh, musisz ograniczyć się do instrukcji POSIX w swoim skrypcie. (Zaletą jest to, że dashzaczyna się szybciej niż bash, dzięki czemu skrypt może wykonać swoją pracę w krótszym czasie).

Na wielu (większości?) Innych systemach Linux /bin/shjest bash, dlatego wiele skryptów jest napisanych #!/bin/shjako ich linia shebang, mimo że używają bashrozszerzeń.

Jeśli chcesz używać bashrozszerzeń, najbezpieczniejszym podejściem we wszystkich systemach jest określenie #!/bin/bash; w ten sposób wyraźnie określasz swoją zależność bash. Ci potrzeba , aby to zrobić na Debianie i Ubuntu. Jako dodatkowy bonus, gdy uruchamiany jako /bin/sh bashdezaktywuje niektóre rozszerzenia (szczegółowe informacje można znaleźć w opisie bashtrybu POSIX ); więc określenie #!/bin/bashjest konieczne, aby w pełni wykorzystać bash.

Na OS X /bin/bashjest również dostępny i /bin/shjest bash. Określanie również #!/bin/bashbędzie działać dobrze.

Stephen Kitt
źródło
5

Tak, zarówno OSX, jak i Linux /bin/bash. Powinieneś być całkowicie bezpieczny. Nie jest to jednak POSIX. Powłoka POSIX jest w /bin/shwiększości (wszystkich?) Systemach i jest to najbardziej przenośne podejście i jedyny sposób na kompatybilność z POSIX.

Zauważ, że podczas gdy w wielu systemach /bin/shwskazuje bash, w innych może wskazywać na różne powłoki. Jest to na przykład dowiązanie symboliczne do dashDebiana i Ubuntu. Ponadto, nawet jeśli /bin/shjest to link do bash, zachowanie powłoki zmienia się, gdy jest ona wywoływana jako sh(z man bashmojego wyróżnienia):

Jeśli bash jest wywoływany z nazwą sh, próbuje naśladować zachowanie startowe historycznych wersji sh tak dokładnie, jak to możliwe, przy jednoczesnym zachowaniu zgodności ze standardem POSIX. Wywoływany jako interaktywna powłoka logowania lub nieinteraktywna powłoka z opcją --login, najpierw próbuje odczytać i wykonać polecenia z / etc / profile i ~ / .profile, w tej kolejności. Opcji --noprofile można użyć do zahamowania tego zachowania. Przywoływany jako interaktywna powłoka o nazwie sh, bash szuka zmiennej ENV, rozszerza jej wartość, jeśli jest
zdefiniowano i używa wartości rozwiniętej jako nazwy pliku do odczytu i wykonania. Ponieważ powłoka wywoływana jako sh nie próbuje czytać i wykonywać poleceń z innych plików startowych, opcja --rcfile nie ma wpływu. Nieinteraktywna powłoka wywołana nazwą sh nie próbuje odczytać żadnych innych plików startowych. Przywołany jako sh, bash przechodzi w tryb posiksowy po odczytaniu plików startowych.

terdon
źródło
2

Jeśli zgodność z „wszystkimi systemami uniksowymi” jest bezwzględnym wymogiem - a jeśli nie, to dlaczego piszesz skrypt powłoki? - więc tak, powinieneś używać #! /bin/sh, ponieważ Bash nie ma gwarancji, że zostanie zainstalowany w dowolnym miejscu , a co dopiero w nim /bin.

To właściwie dużo, dużo gorzej. Jeśli potrzebujesz kompatybilności ze wszystkimi systemami uniksowymi, w tym takimi jak Solaris i AIX, które zamroziły swoje środowiska powłoki około 1995 roku. Co oznacza, że ​​musisz używać rzeczy takich jak staromodna sort +Nskładnia - że nowsze systemy spadły! Oznacza to również brak funkcji powłoki, brak tablic, nie [[ ... ]], nie ${foo#glob}, nie $(( ... ))dla arytmetyki, być może brak $( ... )podstawiania poleceń w stylu, małe i nieudokumentowane górne limity, jak duże mogą być dane wejściowe, ...

Prawdopodobnie można uciec z nie przeszkadza przy tym dużo kompatybilności, ale jeśli jest to nawet problem w pierwszej kolejności, gorąco polecam wziąć pod uwagę język, który jest mniej straszny niż powłoki. Podstawowy interpreter Perla jest bardziej dostępny niż Bash.

Zwol
źródło
Dzięki. Jak pierwotnie stwierdzono: „W moim przypadku jedynym systemem, na którym mi zależy, jest Ubuntu (Debian) i OSX.”. Są to jedyne 2 systemy, z których korzystałem (i używam ich często) w ciągu ostatnich 5 lat, więc „dlatego” piszę skrypt powłoki, który tylko na nich działa. W ogóle nie potrzebuję uniwersalnego skryptu i ograniczeń, jakie by na nim stwarzało.
Michael Durrant
@MichaelDurrant W takim przypadku nie musisz i nie powinieneś pisać skryptu powłoki. Zamiast tego powinieneś użyć jednego z wielu lepszych języków skryptowych, które są opcją, gdy nie potrzebujesz całkowitej przenośności.
zwolnienie