Czy jest jakiś powód, aby shebang wskazywał / bin / sh zamiast / bin / bash?

53

W większości skryptów powłoki, które widziałem (oprócz tych, których sam nie napisałem), zauważyłem, że shebang jest ustawiony na #!/bin/sh. Tak naprawdę nie zaskakuje mnie to w przypadku starszych skryptów, ale dotyczy to również całkiem nowych skryptów.

Czy jest jakiś powód, by preferować coś /bin/shwięcej /bin/bash, skoro bashna wielu maszynach z Linuksem i BSD jest to dość wszechobecny i często domyślny program sprzed dekady?

Jules
źródło
23
Dobrym rozwiązaniem jest stosowanie, /bin/shjeśli nie korzystasz z określonych bashfunkcji. Pewnego dnia możesz użyć jednego ze skryptów w systemie, w którym nie jest on zainstalowany (serwer zdalny, komputer wbudowany ...)
Mathieu,
1
ogólnie powinieneś unikać zadawania pytań, na które można odpowiedzieć na podstawie opinii (to jedyny możliwy sposób, w jaki wierzę, że można na nie odpowiedzieć - ale to tylko moja opinia ) .
mikeserv
9
Uważam, że można odpowiedzieć na to pytanie bez udziału zwykłej opinii, wskazując przynajmniej dwie organizacje, które zajmowały się tą kwestią przez wiele lat, i patrząc na historię i wyniki. Z mnóstwem dalszych lektur, aby uruchomić. ☺
JdeBP
3
@JulesMazur ...the answers so far are fairly subjective...„Subiektywne” stwierdzenie jest z definicji oparte na opiniach. /bin/bashpowinien być używany tylko wtedy, gdy bash jest wyraźnie potrzebny. Przez ponad 40 lat jako programista, na długo przedtem bash, prawie nigdy nie potrzebowałem tego wyraźnie , z wyjątkiem testów. (Staram się również unikać rozszerzeń powłoki, ale większość moich skryptów jest przeznaczona do dystrybucji.) Wiele skryptów w sieci powinno być również przeznaczonych do szerokiego użytku.
user2338816,
2
@ user2338816 mój zły, miałem na myśli cel . Dzięki za twoje punkty!
Jules

Odpowiedzi:

83
  1. Są systemy domyślnie nie wysyłające bash (np. FreeBSD).
  2. Nawet jeśli bash jest zainstalowany, może się nie znajdować /bin.
  3. Większość prostych skryptów nie wymaga bash.
  4. Korzystanie z powłoki POSIX jest bardziej przenośne, a skrypty będą działać na większej liczbie systemów.
Marco
źródło
17
Kolejny powód: często / bin / sh jest szybszy niż bash lub przynajmniej ładuje się szybciej (ze względu na to, że jest mniejszy).
derobert
5
@derobert, /bin/shjest szybszy, jeśli nie jest bash, wciąż istnieje kilka systemów, takich jak OS / X lub RHEL, gdzie /bin/shjest bash.
Stéphane Chazelas,
1
Nie. Niektóre systemy operacyjne go łączą, ponieważ bash jest wstecznie kompatybilny.
Sobrique,
7
Zakłada się, że /bin/shjest to całkiem sporo skryptów /bin/bash. Przełączanie Ubuntu z bash na dash zepsuło wszystkie z nich.
atamanroman
19
@atamanroman: Skrypty były przede wszystkim niepoprawne, powinny były zostać użyte, #!/bin/bashgdyby chcieli Bash (nic złego z tym!). Zmiany dokonano głównie na wcześniejszym etapie w Debianie. Poprawił komfort użytkowania, miał wymierny wpływ na czas uruchamiania systemu. Wpłynęło to również pozytywnie na bezpieczeństwo, patrz „Shellshock”.
Dietrich Epp,
28

Większość skryptów systemowych w (związanych z Debianem: Ubuntu, Mint itp.) Linux jest napisanych tak, aby działały w szybszym myślniku, który jest domyślnym / bin / sh w tych systemach. Powód jest dwojaki:

  • Szybkość systemu. Mniejszy kod myślnika ładuje się szybciej, a także działa szybciej. Z pewnym (małym?) Dodatkowym wysiłkiem (kosztem) dla programistów skryptów powłoki.

  • Bezpieczeństwo. Różnorodność powłok pomaga w odporności na błędy. Systemy Debian nie były w większości podatne na wstrząs, ponieważ domyślna powłoka nie miała takiej podatności.

Bash jest rzeczywiście domyślną powłoką dla użytkowników , ponieważ jest bardziej wydajny i zawiera znacznie więcej elementów, aby ułatwić kodowanie. Jest to również domyślny shw Mac OS (ten, do którego prowadzi link z / bin / sh). Jednak wywołanie bashz nazwą łącza shpowoduje, że zaczyna się jako powłoka zgodna z posix.


źródło
2
Bardziej ograniczony zestaw dostępnych narzędzi prostszej powłoki sprawia, że ​​pisanie kodu jest trudniejsze (unikaj fanatycznej wojny na ten temat). Dlatego niektórzy użytkownicy lubią zsh, który ma jeszcze więcej dostępnych narzędzi niż bash. Bardziej podoba mi się Bash, a także równowaga między obiema skrajnościami.
4
@RobertL, istnieje wiele udogodnień dodanych do ksh i przyjętych przez bash, ponieważ znacznie ułatwiają one pisanie solidnych i poprawnych skryptów. Bez różnych dodatków umożliwiających bezpieczne pośrednie przypisanie i ocenę, można na przykład znaleźć się przy użyciu eval, z towarzyszącym narażeniem bezpieczeństwa; podobnie, bez wbudowanej obsługi wyrażeń regularnych, może być konieczne użycie poleceń zewnętrznych (z dużym obciążeniem wydajnościowym) w celu dopasowania nawet w obrębie jednej linii itp.
Charles Duffy,
1
@RuiFRibeiro, nic nie jest statycznie powiązane w Debianie. Dash jest bardziej ograniczony, ale jest ograniczony głównie funkcjami interaktywnymi (bez ukończenia i tym podobnych), dzięki czemu jest szybszy dla skryptów.
Jan Hudec
21

Inni zauważyli, że przesłanki pytania, że ​​powłoka Bourne Again jest domyślna i wszechobecna, są całkowicie błędne.

Poza tym istnieją naprawdę dobre powody, aby używać do interpretacji skryptów powłoki czegoś innego niż powłoka Bourne Again. Przyczyny te zmotywowały duży projekt Ubuntu i Debiana, przez wiele lat, do usunięcia bashism i spowodowania, aby tyle skryptów powłoki było uruchamianych przez inicjalizację systemu (która była dużą ilością skryptów powłoki w Systemie 5 rc), a instalacja / usuwanie pakietów korzystała z Powłoka Almianist Debiana zamiast powłoki Bourne Again.

Mówiąc wprost: powłoka Bourne Again, pełna interaktywnych funkcji, nie jest najszybszym interpretatorem powłoki dla skryptu zgodnego z POSIX. Jeśli więc można stworzyć własne skrypty powłoki zgodne z POSIX, interpretując je za pomocą lżejszego programu, takiego jak powłoka Debian Almquist, system będzie działał lepiej. (Ostatecznie Debian musiał dokonać drobnych zmian w powłoce Almquist, aby dodać obsługę kilku konstrukcji powłok innych niż POSIX, które były po prostu zbyt głęboko i szeroko osadzone i zbyt przydatne, aby się ich pozbyć.)

Wynikiem tego wszystkiego był znaczny wzrost wydajności ładowania początkowego.

Istnieją tutaj dwie odrębne klasy powłok:

  • Powłoki ze wszystkimi krzykliwymi funkcjami interaktywnymi, które są skonfigurowane jako interaktywne powłoki logowania dla użytkowników w bazie danych kont.
  • Powłoki, które szybko interpretują wiele skryptów, które są używane jako interpretatory skryptów przez programy skryptów powłoki.

Zauważ, że mówienie o tym jako o „preferowaniu /bin/sh” jest nadmiernym uproszczeniem. Debian miał przynajmniej dwa cele:

  1. W obliczu administratorów używających powłoki Debian Almquist, powłoki Z (w trybie POSIX), powłoki Bourne Again (w trybie POSIX), powłoki MirBSD Korn i innych /bin/sh, ponieważ albo…

    1. … Czyniąc skrypty tak przenośnymi, jak to możliwe, aby przełączanie /bin/shmapowanych elementów nie powodowało uszkodzenia ; lub

    2. … Tworzenie nieprzenośnych skryptów wyraźnie celuje we właściwy program interpretera , zamiast po prostu oczekiwać /bin/shod niego mapy.

  2. Było czyniąc Almquist Debian powłoki domyślne odwzorowania dla /bin/shzamiast Bourne Shell, tak że te skrypty, które były POSIX-conformant (lub, bardziej poprawnie, Debian Policy Instrukcja conformant) biegł szybciej.

I oczywiście, kiedy się w to zagłębi, można pójść o wiele dalej; takich jak uznając kompromisów sprawność pokroju /bin/truei /usr/bin/clearjest skrypty powłoki lub skompilowane programy. Na szczęście wykracza to poza zakres tej odpowiedzi. ☺

Nic z tego nie jest oczywiście nowe, ani nawet specyficzne dla Uniksa. Jeszcze przed przełomem wieku napisałem i opublikowałem interpretera wiersza poleceń, który pojawiał się zarówno w wersji „interaktywnej”, jak i „nieinteraktywnej”, wyjaśniając ten podział w swoim doco i zwracając uwagę na różnicę między zmiennymi środowiskowymi COMSPECa OS2_SHELLzmiennymi. Podobnie dyskusja na temat usuwania baszizmów w Systemie V Debiana rci skryptach instalacji / usuwania pakietów sięga lat 90.

Dalsza lektura

JdeBP
źródło
2
„Ostatecznie Debian musiał dokonać drobnych zmian w powłoce Almquist, aby dodać obsługę kilku konstrukcji powłok innych niż POSIX, które były po prostu zbyt głęboko i szeroko osadzone i zbyt przydatne, aby się ich pozbyć”. - Który z twoich wielu linków zawiera informacje na ten temat? Brzmi bardzo interesująco. :)
Wildcard
3
IMHO, wydajność jest tylko motywacją, aby ludzie zgodzili się na zmiany. Początkowym ważnym powodem zmiany było to, że bash ciągle łamał kompatybilność wsteczną. Osobiście musiałem naprawiać problemy z bash co najmniej 3 razy w mojej karierze, ponieważ skrypt działałby w jednej wersji bash, ale w innej nie powiódł się (zwykle dzieje się to po aktualizacji systemu operacyjnego). Dash to nie tylko nieco szybszy tłumacz. Jest również znacznie bardziej stabilny pod względem zachowania.
slebetman
Byłbym zainteresowany, czy komentarze na Schily Bourne Shellstronie man, patrz schilytools.sourceforge.net/bosh.html są odpowiednie, aby umożliwić ludziom zrozumienie, jak napisać przenośny skrypt (to zależy tylko Bourne Shell featuresod 1989 roku). To, co zrobiłem, to wspomnienie o każdym ulepszeniu, którego nie było w starych Skorupach Bourne'a. BTW: Interesuje mnie również lista baszizmów w desce rozdzielczej.
schily
8

Czy jest jakiś powód, aby shebang wskazywał / bin / sh zamiast / bin / bash?

Tak. Doskonała odpowiedź @ Marco przedstawia to dobrze.

Czego powinienem użyć w moim shebang?

Pisząc własne skrypty, powinieneś wskazać skrót na najbardziej ogólną rzecz, na której testowałeś.

W moim systemie (Centos 6.6) shjest dowiązanie symboliczne do bash:

$ ls -l /bin/sh 
lrwxrwxrwx 1 root root 4 Dec  2  2014 /bin/sh -> bash

Oznacza to, że zawsze używam #!/bin/bashw shebang, chyba że potwierdzę, że nie mam bashimów w moim skrypcie.

Ustawiając shebang #!/bin/sh, obiecujesz, że skrypt będzie działał ze wszystkimi implementacjami sh.

Jest to znacznie większa obietnica niż stwierdzenie, że skrypt będzie działał z bash.

Oto przykład skryptu, który będzie działał niepoprawnie w zależności od shimplementacji używanej przez system:

#!/bin/sh
n=1
a=$((++n))
echo $n

Podczas korzystania bashze skryptu wydrukujemy:

2

Podczas korzystania dashze skryptu wydrukujemy:

1

Jeśli chcę użyć #!/bin/shtego, co muszę zrobić?

  • Sprawdź skrypt za pomocą checkbashisms- Zauważ, że nie znajdzie to wszystkich bashimów. Nie znalazłem bashizmu w moim skrypcie powyżej
  • Przetestuj skrypt za pomocą innej shimplementacji. Zazwyczaj dashtestuję, ale spodziewam się, że niektóre bashizmy lub dashimy mogą się jeszcze przedostać.

Strona DashAsBinSh na wiki Ubuntu zawiera wiele interesujących informacji.

sześćdziesiąt stóp
źródło
6
„Pisząc własne skrypty, powinieneś wskazać shebang na najbardziej ogólną rzecz, którą przetestowałeś… Ustawiając shebang na #! / Bin / sh, obiecujesz, że skrypt będzie działał ze wszystkimi implementacjami sh . ” Doskonały punkt +1, a ty zmusiłeś mnie do przemyślenia, w jaki sposób napiszę moje shebangi na przyszłość. Dziękuję Ci! :)
Wildcard
2
Cóż, nie wszystkie implementacje /bin/sh; tylko te zgodne z POSIX.
Blacklight Shining
4

Jedynym pozostałym powodem napisania skryptu powłoki zamiast skryptu w bardziej wydajnym i ergonomicznym języku jest to, że przenośność na starszych systemach z nieznanym zestawem zainstalowanego oprogramowania jest ważniejsza niż jakikolwiek inny czynnik .

/bin/shto jedyny interpreter skryptów dostępny we wszystkim, co nazywa się Unix. Ale na okropnej liczbie starszych systemów /bin/shi powiązane narzędzia nie są nawet zgodne ze specyfikacją POSIX.1-1996 dotyczącą „powłoki i narzędzi”, nie mówiąc już o czymś bardziej nowoczesnym. Narzędzia zgodne ze standardami to opcjonalny dodatek, zainstalowany w /usr/xpg4takiej lub nieoczywistej lokalizacji. 1 Skrypty do języka powłoki z przenośnym podzbiorem są jeszcze bardziej uciążliwe i podatne na błędy niż skrypty do języka powłoki POSIX. (Przeczytaj configurekiedyś skrypt wygenerowany przez Autoconf, jeśli mi nie wierzysz. Wystarczy konfiguracja, aby cię przekonać).

Ale jeśli możesz założyć, że jest zainstalowany jakikolwiek inny interpreter skryptów (np. Bash), możesz założyć interpreter dla lepszego języka skryptowego . Na przykład Perl jest bardziej dostępny niż Bash.

Dlatego nigdy nie powinieneś pisać #! /bin/bashskryptu, ponieważ jeśli jest to opcja, lepszym językiem jest również opcja.

1 Na przykład Solaris 10 i starsze dostarczały oryginalną powłokę Bourne'a jako /bin/sh. Zostałem poinformowany, że Solaris 11 zaktualizował go do ksh93.

zwol
źródło
3
W jakim języku napiszesz skrypt do uruchomienia systemu? Lub wewnątrz routera SOHO (ograniczone systemy z embebagowaniem)? Lub w Androidzie? Powłoka będzie dostępna we wszystkich tych przypadkach. Perl nie.
1
Istnieją pewne nieścisłości dotyczące części twojej odpowiedzi dotyczącej systemu Solaris. W systemie Solaris 10 i starszych nie/bin/sh jest POSIX.1-1996, ale w rzeczywistości oryginalną powłoką Bourne'a o składni sprzed POSIX. To sprawia, że skrypt jest bardzo kiepski, jeśli chodzi o uruchamianie skryptów w tych wydaniach. Używałyby przenośne skrypty w systemie Solaris, które nie będą bardzo przenośne w innych systemach operacyjnych. W najnowszym Solarisie Oracle Solaris 11 po raz pierwszy wydany w 2011 r. Jest nowoczesnym urządzeniem, które jest zgodne z najnowszymi specyfikacjami POSIX i ma wiele nowoczesnych rozszerzeń. #!/bin/sh#!/usr/xpg4/bin/sh/bin/shksh93
jlliagre
1
@BinaryZebra: „Powłoka” będzie dostępna, tak. Ale bash niekoniecznie jest tą powłoką (w szczególności większość routerów SOHO, ashktóre są dostarczane z busybox), i myślę, że zwolnienie ma rację, że perl jest częściej dostępny niż bash.
Ben Voigt,
1
@BenVoigt Komentuję to zdanie: „Jedyny pozostały powód do napisania skryptu powłoki”. Nadal istnieją pewne przypadki, które wymagają powłoki do niektórych zadań (nie wszystkie). To były niektóre przypadki ze szczytu mojej głowy. OTOH W systemach z wystarczającą ilością pamięci (prawie wszystkie w dzisiejszych standardach) i wystarczającą mocą instalowanie Perla (lub Pythona lub…) jest dość szybkie i łatwe. Nie jestem jednak zwolennikiem żadnej konkretnej powłoki. Gdzie to czytasz w moim komentarzu?
2
Nie zgadzaj się całkowicie z twoim wysoce upartym i niefaktycznym twierdzeniem, że „jeśli bashjest dostępny, to jest lepszy język, więc nigdy nie powinieneś pisać żadnego bashkodu”. Ponadto, jak wskazuje @sixtyfootersdude, powinieneś zawsze używać, #!/bin/bashchyba że sprawdziłeś, czy twój skrypt działa z dowolną powłoką POSIX.
Wildcard
0

Powinieneś faktycznie użyć albo

#! /bin/env sh

lub

#! /bin/env bash

w ten sposób wywołujesz dowolną powłokę według sposobu instalacji w tym systemie.

Aby być bardzo bezpiecznym ( np. W przypadku restartów dla jednego użytkownika), używaj w shinny sposób bash.

Paul Evans
źródło
6
Z tej odpowiedzi : the advantage of #!/usr/bin/env python is that it will use whatever python executable appears first in the user's $PATH. The disadvantage of #!/usr/bin/env python is that it will use whatever python executable appears first in the user's $PATH.prawdopodobnie dotyczy to również shi bash.
Jules
12
Nie, nie powinieneś używać #!/bin/envniczego w przenośnym skrypcie. Całkowicie uzasadnione jest założenie, że /bin/shistnieje i jest działającą powłoką zgodną z POSIX. Z drugiej strony żaden z moich systemów nie ma /bin/env.
Blacklight Shining
Również dobra uwaga.
Jules
1
@Blacklight Świecenie jest zdecydowanie błędem przy zakładaniu powłoki zgodnej z POSIX /bin/sh. POSIX nie wymaga tego i raczej definiuje inne reguły, aby uzyskać środowisko zgodne z POSIX na certyfikowanej platformie POSIX.
schily
4
/usr/bin/envnie jest powszechnie dostępny ...
vonbrand,