Jaki jest preferowany shebang Bash?

1127

Czy istnieje jakikolwiek Bashshebang obiektywnie lepszy od innych do większości zastosowań?

  • #!/usr/bin/env bash
  • #!/bin/bash
  • #!/bin/sh
  • #!/bin/sh -
  • itp

Niegdyś pamiętam dawno temu, że dodanie kreski na końcu uniemożliwia komuś przekazanie polecenia do twojego skryptu, ale nie może znaleźć żadnych szczegółów na ten temat.

Kurtosis
źródło
4
I jest /usr/local/bin/bashna OpenBSD.
jww

Odpowiedzi:

1532

Powinieneś użyć #!/usr/bin/env bashdla przenośności : różne * nixy umieszczone bashw różnych miejscach, a użycie /usr/bin/envjest obejściem do uruchomienia pierwszego bashznalezionego na PATH. I shnie jestbash .

l0b0
źródło
9
Dzięki. Wygląda również na dodanie - na końcu $! / Usr / bin / env bash - nic nie zrobi, ponieważ * nix w shebang zezwala tylko na jeden argument i jest on używany przez 'bash'. Jest to najwyraźniej przydatne tylko w celu zapobiegania przekazywaniu złośliwych argumentów do skryptu w wierszu poleceń, jeśli shebang skryptu jest jednym z pozostałych bez argumentów ( /bin/shitp.).
Kurtosis
13
@Ray bashnie działa we /binwszystkich systemach.
ptierno
12
To samo dla mnie, właśnie dodałem go do aliasu: alias shebang='echo "#!/usr/bin/env bash"'teraz muszę po prostu otworzyć terminal i wpisać shebang zamiast iść tutaj.
Oylex
19
Ta odpowiedź jest zwodnicza. POSIX nie twierdzi, że envjest na /usr/bin/env. W rzeczywistości może być w /bin/envdowolnym miejscu, o ile jest na ścieżce. Może być w, /dummy/envjeśli /dummyjest w PATH. Sam Shebang jest niezdefiniowany w POSIX, więc mogłem #!stop toasteruruchomić ekspres do kawy USB i być zgodny z POSIX. Więc #!/usr/bin/env bashnie jest szczególnie lepszy niż #!/bin/bash, może być mniej przenośny w zależności.
darkfeline
19
@darkfeline Przenośność nie jest absolutna - matematycznie niemożliwe jest stworzenie skryptu, który zrobiłby to samo na każdej platformie. Od 2012 r. Do 2018 r. /usr/bin/envIstnieje na większej liczbie komputerów niż na którymkolwiek z /bin/bashXorów /usr/bin/bash, więc skrypt rozpoczynający się od tej linii wykona oczekiwaną czynność na jak największej liczbie komputerów.
l0b0
80

/bin/shjest zwykle linkiem do domyślnej powłoki systemu, która często jest bashwłączona, ale np. systemy Debian mają mniejszą wagę dash. Tak czy inaczej, oryginalna powłoka Bourne'a jest shtaka, więc jeśli twój skrypt używa pewnych bash(2. generacji, „Bourne Again sh”) specyficznych funkcji ( [[ ]]testów, tablic, różnych słodkich rzeczy itp.), Powinieneś być bardziej szczegółowy i użyć później . W ten sposób w systemach, w których bash nie jest zainstalowany, twój skrypt nie będzie działał. Rozumiem, że może być ekscytująca trylogia filmów o tej ewolucji ... ale to może być słyszenie.

Zauważ też, że gdy wywoływany jako sh, bashdo pewnego stopnia zachowuje się jak standard POSIX sh (zobacz także dokumentację GNU na ten temat).

delikatna gorączka
źródło
2
Public Domain Korn Shell (pdksh) jest domyślny w OpenBSD.
jww
Większość systemów nie będzie łączyła się /bin/shz nigdzie indziej, /usrponieważ utrudniłoby to uruchamianie skryptów init przed /usrzamontowaniem.
aij
@aij nie wiem dlaczego kładę „wiele lub większość” nie - jestem użytkownik fedora, gdzie /bini /sbinprzez lata właśnie zostały dowiązania domyślnie, aby /usr/bini /usr/sbintak w tym kontekście /bin/shjest link do basha rzeczywistą katalog jest /usr/bin. Ale poprawię powyższe.
Delikatna
43

Polecam użycie:

#!/bin/bash

Nie jest w 100% przenośny (niektóre systemy umieszczają bashw lokalizacji innej niż /bin), ale fakt, że wiele istniejących skryptów używa #!/bin/bashpresji różnych systemów operacyjnych, aby stworzyć /bin/bashprzynajmniej dowiązanie symboliczne do głównej lokalizacji.

Alternatywa dla:

#!/usr/bin/env bash

zostało zasugerowane - ale nie ma gwarancji, że envpolecenie jest w /usr/bin(i użyłem systemów, których nie ma). Ponadto w tym formularzu będzie używana pierwsza instancja bashobecnych użytkowników $PATH, która może nie być odpowiednią wersją powłoki bash.

(Ale /usr/bin/envpowinien działać na każdym dość nowoczesnym systemie, ponieważ envjest w /usr/binsystemie lub dlatego, że system robi coś, co sprawia, że ​​działa. System, o którym mówiłem powyżej, to SunOS 4, którego prawdopodobnie nie używałem od około 25 lat.)

Jeśli potrzebujesz skryptu, aby działał w systemie, który go nie ma /bin/bash, możesz zmodyfikować skrypt, aby wskazywał właściwą lokalizację (co jest oczywiście niewygodne).

Bardziej szczegółowo omówiłem kompromisy w mojej odpowiedzi na to pytanie .

Trochę niejasna aktualizacja: jeden system, którego używam, Termux , warstwa podobna do Linuksa, która działa pod Androidem, nie ma /bin/bash( bashjest /data/data/com.termux/files/usr/bin/bash) - ale ma specjalną obsługę do obsługi #!/bin/bash.

Keith Thompson
źródło
3
2 lata później i to wciąż najlepsza rada tutaj. Jeśli proste rozwiązanie nie działa, musisz zakwestionować swoje wcześniejsze decyzje. Przyjęta i najbardziej uprzywilejowana odpowiedź nie jest zła, po prostu jest niewłaściwa :)
Inżynier oprogramowania
26

Użycie linii shebang do wywołania odpowiedniego tłumacza jest nie tylko dla BASH. Możesz użyć shebang dla dowolnego języka interpretowanego w twoim systemie, takiego jak Perl, Python, PHP (CLI) i wiele innych. Nawiasem mówiąc, shebang

#!/bin/sh -

(mogą to być również dwa myślniki, tj. --) kończy opcje bash wszystko później będzie traktowane jako nazwy plików i argumenty.

Użycie envpolecenia sprawia, że ​​skrypt jest przenośny i umożliwia konfigurację niestandardowych środowisk dla skryptu, dlatego należy używać przenośnych skryptów

#!/usr/bin/env bash

Lub dla dowolnego języka, takiego jak Perl

#!/usr/bin/env perl

Pamiętaj, aby spojrzeć na manstrony dla bash:

man bash

i env:

man env

Uwaga: W systemach Debian i systemach opartych na Debianie, takich jak Ubuntu, shjest to powiązane z dashnot bash. Jak używają wszystkie skrypty systemowe sh. To pozwala bashowi rosnąć i system pozostaje stabilny, zgodnie z Debianem.

Ponadto, aby zachować wywołanie * nix, tak jak nigdy nie używam rozszerzeń plików w skryptach wywoływanych przez shebang, ponieważ nie można pominąć rozszerzenia wywołania w plikach wykonywalnych, jak to możliwe w systemie Windows. Polecenie file może zidentyfikować go jako skrypt.

Jamie R Robillard Sr.
źródło
4

To naprawdę zależy od tego, jak piszesz skrypty bash. Jeśli twój /bin/shjest symlinkowany do bash, kiedy bash jest wywoływany jako sh, niektóre funkcje są niedostępne .

Jeśli chcesz funkcji specyficznych dla basha, nie POSIX-owych, użyj #!/bin/bash

Glenn Jackman
źródło
3
Bash nie jest zainstalowany na OpenBSD. Jeśli zainstalujesz go za pośrednictwem pkg_add, to znajduje się w /usr/local/bin, co może nie być na drodze.
jww
co z POSIXfunkcją?
Nikolan Asad