Kiedy jest #!/bin/bash
bardziej odpowiednie niż #!/bin/sh
w skrypcie powłoki?
linux
shell-script
Hendré
źródło
źródło
bash
funkcji i składni zamiastsh
funkcji i składni.vim
to podkreślibash
-izm, jeśli twój skrypt ma#!/bin/sh
shebang. Zmieniam to tylkobash
wtedy, gdy robi się wystarczająco owłosiony, aby zacząć potrzebować funkcji bash.$(...)
jest szczególnie wstrętny. Ponadto niektóre z nich są subtelne [<(...)
icmd >& file
nie pojawiają się żadne błędy podświetlania, na przykład po prostu nie mają specjalnego wyróżnienia dla tego, co mają na myśli, z lub bezg:is_bash
]Odpowiedzi:
W skrócie:
Istnieje kilka powłok, które implementują nadzbiór specyfikacji sh POSIX . W różnych systemach
/bin/sh
może być link do ash, bash, dash, ksh, zsh i c. (Zawsze będzie jednak kompatybilny z sh - nigdy nie csh ani ryb.)Tak długo, jak trzymasz się
sh
tylko funkcji, możesz (a prawdopodobnie nawet powinien) używać,#!/bin/sh
a skrypt powinien działać dobrze, bez względu na to, która to powłoka.Jeśli zaczniesz używać funkcji specyficznych dla basha (np. Tablic), powinieneś poprosić bash - ponieważ nawet jeśli
/bin/sh
już wywołuje bash w twoim systemie, może nie być w systemie wszystkich innych i twój skrypt tam nie uruchomi. (To samo oczywiście dotyczy zsh i ksh.) Możesz użyć shellcheck, aby zidentyfikować bashisms.Nawet jeśli skrypt jest tylko do użytku osobistego, możesz zauważyć, że niektóre systemy operacyjne zmieniają się
/bin/sh
podczas aktualizacji - np. W Debianie był bash, ale później został zastąpiony bardzo minimalnym myślnikiem. Skrypty, które używały bachizmów, ale#!/bin/sh
nagle się zepsuły.Jednak:
Nawet
#!/bin/bash
nie jest bardzo poprawne. W różnych systemach bash może żyć w/usr/bin
lub/usr/pkg/bin
lub/usr/local/bin
.Bardziej niezawodną opcją jest
#!/usr/bin/env bash
użycie zmiennej PATH. (Chociażenv
samo narzędzie nie jest również ściśle gwarantowane,/usr/bin/env
nadal działa na większej liczbie systemów niż/bin/bash
działa).źródło
/bin/sh
wówczas spróbuje on naśladowaćsh
funkcje (patrz strona podręcznika ), nie jestem pewien, czy w tym trybie dostępne są określone funkcje bash.env
Narzędzie to jest narzędziem posiksowym, które należy znaleźć w większości dystrybucji, ale nie jestem pewien, ponieważ niektórzy mogą nie uszanować posix./bin
: „ Aplikacje powinny pamiętać, że nie można założyć, że standardową ścieżką do powłoki jest / bin / sh lub / usr / bin / sh, i należy ją określić przez zapytanie PATH zwrócone przez getconf PATH, upewniając się, że zwracana ścieżka jest absolutną ścieżką, a nie wbudowaną powłoką ". Zobacz także to pytanie, a konkretnie tę odpowiedź .#!
działania skryptów?echo foo ^ cat
emitujefoo ^ cat
w POSIX sh i emituje tylkofoo
w Bourne (podobnie jak^
znak potoku).Użyj shebang odpowiadającego powłoce, której faktycznie użyłeś do opracowania i debugowania skryptu. To znaczy
bash
, jeśli twoja powłoka logowania jest uruchomiona, a skrypt uruchamiasz się w terminalu jako wykonywalny, użyj#!/bin/bash
. Nie zakładaj tylko, że skoro nie używałeś tablic (ani żadnej innej znanejbash
Ci funkcji), możesz bezpiecznie wybrać dowolną powłokę. Istnieje wiele subtelnych różnic między powłokami (echo
, funkcjami, pętlami, jak to nazywasz), których nie można wykryć bez odpowiedniego testowania.Zastanów się: jeśli odejdziesz,
#!/bin/bash
a twoi użytkownicy go nie mają, zobaczą wyraźny komunikat błędu, coś w rodzajuWiększość użytkowników może to naprawić w ciągu jednej minuty, instalując odpowiedni pakiet. Z drugiej strony, jeśli zastąpisz shebang przez
#!/bin/sh
i przetestujesz go w systemie, w którym/bin/sh
znajduje się dowiązanie symboliczne/bin/bash
, Twoi użytkownicy, którzy go nie mają,bash
będą mieli kłopoty. Najprawdopodobniej zobaczą tajemniczy komunikat o błędzie, taki jak:Naprawienie tego może potrwać kilka godzin i nie będzie żadnych wskazówek, która powłoka powinna była użyć.
Nie ma wielu powodów, dla których chciałbyś użyć innej powłoki w shebang. Jednym z powodów jest to, że używana powłoka nie jest powszechna. Innym jest uzyskanie wydajności,
sh
która jest znacznie szybsza w niektórych systemach, A twój skrypt będzie wąskim gardłem wydajności. W takim przypadku dokładnie przetestuj skrypt za pomocą docelowej powłoki, a następnie zmień shebang.źródło
Powinieneś tylko używać
#! /bin/sh
.Nie powinieneś nigdy używać rozszerzeń bash (lub zsh, fish, lub ...) w skrypcie powłoki.
Powinieneś pisać tylko skrypty powłoki, które działają z dowolną implementacją języka powłoki (w tym ze wszystkimi programami „narzędziowymi”, które towarzyszą samej powłoce). W dzisiejszych czasach prawdopodobnie możesz uznać POSIX.1-2001 ( nie -2008) za wiarygodne dla tego, co potrafi powłoka i narzędzia, ale pamiętaj, że pewnego dnia możesz zostać poproszony o przeniesienie skryptu do starszego systemu (np. Solaris lub AIX), którego skorupa i narzędzia zostały zamrożone około 1992 r.
Poważnie ?!
Tak poważnie.
Oto rzecz: Shell to straszny język programowania. Jedyne, co ma do tego, to to, że
/bin/sh
jest to jedyny interpreter skryptów, który gwarantuje każda instalacja uniksowa.Oto druga rzecz: pewna iteracja podstawowego interpretera Perl 5 (
/usr/bin/perl
) jest bardziej dostępna w losowo wybranej instalacji Unixa niż(/(usr|opt)(/(local|sfw|pkg)?)?/bin/bash
jest. Inne dobre języki skryptowe (Python, Ruby, node.js itp. - W tej kategorii uwzględnię nawet PHP i Tcl w porównaniu z powłoką) są mniej więcej tak dostępne, jak bash i inne rozszerzone powłoki.Dlatego jeśli masz opcję napisania skryptu bash, możesz zamiast tego użyć języka programowania, który nie jest straszny.
Teraz, proste skrypty powłoki, takie, które po prostu uruchamiają kilka programów w sekwencji z zadania crona lub coś takiego, nie ma nic złego w pozostawieniu ich jako skryptów powłoki. Ale proste skrypty powłoki nie potrzebują tablic ani funkcji, a
[[
nawet. Powinieneś pisać skomplikowane skrypty powłoki tylko wtedy, gdy nie masz innego wyboru. Na przykład skrypty Autoconf są nadal poprawnie skryptami powłoki. Ale te skrypty muszą być uruchamiane przy każdym wcieleniu/bin/sh
istotnym dla konfigurowanego programu. a to oznacza, że nie mogą używać żadnych rozszerzeń. Prawdopodobnie w dzisiejszych czasach nie musisz przejmować się starymi zastrzeżonymi Uniksami, ale prawdopodobnie powinieneś przejmować się obecnymi BSD typu open source, z których niektóre nie instalują siębash
domyślnie oraz środowiska osadzone, które dają tylko minimalną powłokę ibusybox
.Podsumowując, moment znaleźć się chcąc funkcję, która nie jest dostępna w języku powłoki przenośnej, że jest to znak, że skrypt stał się zbyt skomplikowany, aby zatrzymać skrypt. Zamiast tego przepisz go w lepszym języku.
źródło
sh
. Jest to jednak dalekie od stwierdzenia, że nigdy nie powinieneś używać innych pocisków. Każdego dnia pisanych jest tysiące (prawdopodobnie o wiele więcej) skryptów, a zdecydowana większość z nich będzie działała tylko na jednym komputerze. Twoja rada ma sens w przypadku kodu produkcyjnego, ale nie dotyczy codziennych zadań „sysdaminy”, dla których napisano większość skryptów. Jeśli wiem, że mój skrypt będzie używany tylko przeze mnie i na komputerze z systemem Linux, bash jest w porządku.Ogólnie, jeśli czas jest ważniejszy niż funkcjonalność, użyjesz szybszej powłoki. sh jest często aliasowany do myślnika i zwykle jest używany do zadań crona root lub operacji wsadowych, w których liczy się każda (nano) sekunda.
źródło
Mówiąc w skrócie, użyj,
sh
jeśli najważniejsza jest przenośność w większości systemów ibash
jeśli chcesz skorzystać z niektórych jej specyficznych funkcji, takich jak tablice, jeśli obsługuje ją wersja bash.źródło
Najbezpieczniejsza ścieżka. po zapisaniu na stałe będzie to / usr / bin /,
shellOfChoice
ale nowa konwencja, z której zawsze staram się korzystać - jako „domyślne lokalizacje” poprzez zmianę PATH może się zmienić:#! / usr / bin / env sh lub
#! / usr / bin / env bash
lub np. skrypty perl
#! / usr / bin / env perl -w
Oczywiście, jeśli masz powód, aby skrypt NIGDY nie pobierał automatycznie nowej ŚCIEŻKI, to nadal powinien mieć zakodowany na stałe - i wtedy / usr / bin / coś powinno być najbardziej prawdopodobną ścieżką do użycia.
źródło