Czy poprawne jest użycie / bin / sh w haszangu, jeśli powłoka Bourne'a nie jest dostępna w dystrybucji?

15

Ogólnie, skrypty powłoki zawierają następujący komentarz w pierwszym wierszu pliku skryptu: #!/bin/sh. Według przeprowadzonych przeze mnie badań nazywa się to „hash bang” i jest to konwencjonalny komentarz. Ten komentarz informuje Unixa, że ​​ten plik jest wykonywany przez Bourne Shell w katalogu /bin.

Moje pytanie zaczyna się od tego momentu. Do tej pory nie widziałem tego komentarza #!/bin/bash. Tak jest zawsze #!/bin/sh. Jednak dystrybucje Ubuntu nie mają programu Bourne Shell. Mają Bourne Again Shell (bash).

Czy w tym momencie poprawne jest umieszczanie komentarza #!/bin/shw skryptach powłoki napisanych w dystrybucjach Ubuntu?

Goktug
źródło
1
Zobacz moją odpowiedź na to pytanie o usterkę serwera: #! / Bin / sh vs #! / Bin / bash dla maksymalnej przenośności .
Gordon Davisson
Częściej nazywanyshebang
fpmurphy

Odpowiedzi:

16

#!/bin/shpowinien działać na wszystkich dystrybucjach uniksowych i podobnych. Jest to ogólnie uważane za najbardziej przenośny hashbang, o ile skrypt jest zgodny z POSIX. /bin/shPowłoka ma być powłoką, która implementuje powłoki POSIX standard, niezależnie od tego, co rzeczywiste jest to, że powłoka maskarada jako /bin/shpowłoki.


#!/bin/shjest zwykle tylko linkiem, ponieważ powłoka Bourne'a nie jest już utrzymywana. W wielu systemach Unix /bin/shbędzie link do /bin/kshlub /bin/ashna wielu systemach Linux RHEL oparte będzie to link /bin/bash, jednak na Ubuntu i wielu systemów opartych na Debianie jest to link /bin/dash. Wszystkie powłoki, wywołane jako sh, wejdą w tryb zgodności z POSIX.

Hashbang jest jednak ważnym symbolem zastępczym, ponieważ pozwala na znacznie większą przenośność niż inne metody, pod warunkiem, że twój skrypt jest ściśle zgodny z POSIX (co podkreśla znaczenie).

Uwaga: Gdy bashzostanie wywołany w trybie POSIX, nadal będzie dopuszczał niektóre rzeczy inne niż POSIX, takie jak [[tablice i inne. Te rzeczy mogą zawieść w niesystemie bash.

jesse_b
źródło
3
„w Ubuntu jest to link do / bin / dash” i ogólnie innych systemów opartych na Debianie. IIRC na FreeBSD / GhostBSD to również dowiązanie symboliczne /bin/ash.
Sergiy Kolodyazhnyy
Aby być w pełni przenośnym, umieść odstęp między shebang a (absolutną) ścieżką tłumacza. Niektóre systemy szukają #! /zamiast po prostu #!.
Simon Richter
5
@ SimonRichter Miło byłoby zobaczyć odniesienie do tego.
Kusalananda
@SergiyKolodyazhnyy Zainstalowana wersja sh na FreeBSD to ash, a nie dowiązanie symboliczne.
Rob
2
@Kusalananda, hmm, ta strona mówi, że to mit, więc prawdopodobnie można go zignorować.
Simon Richter
12

Masz to zacofane. /bin/shw dzisiejszych czasach prawie nigdy nie jest powłoką Bourne'a i właśnie wtedy masz problem z używaniem She #! /bin/sh-Bang.

Powłoka Bourne'a była powłoką napisaną pod koniec lat 70. i zastąpiła poprzednią powłokę Thompson (zwaną także sh). Na początku lat 80. David Korn napisał kilka rozszerzeń dla powłoki Bourne'a, naprawił kilka błędów i powodował problemy z projektowaniem (i wprowadził kilka) i nazwał ją skorupą Korna.

Na początku lat 90. POSIX określił sh język w oparciu o podzbiór powłoki Korn, a większość systemów obecnie zmieniła swój język na /bin/shpowłokę Korn lub powłokę zgodną z tą specyfikacją. W przypadku BSD stopniowo zmieniali /bin/shpoczątkowo (po tym, jak nie mogli już używać powłoki Bourne'a ze względów licencyjnych) powłokę Almquist, klon powłoki Bourne'a z niektórymi rozszerzeniami ksh, więc stała się zgodna z POSIX.

Obecnie wszystkie systemy POSIX mają powłokę o nazwie sh(najczęściej, ale niekoniecznie w /bin, POSIX nie określa ścieżki określonych przez nią narzędzi), która jest w większości zgodna z POSIX. Zasadniczo jest oparty na ksh88, ksh93, pdksh, bash, ash lub zsh², ale nie na powłoce Bourne'a, ponieważ powłoka Bourne'a nigdy nie była zgodna z POSIX3. Niektóre z tych skorup ( bash, zsh, yashi niektóre pdkshpochodne włączenia trybu do POSIX przy wywołaniu jak shi są mniej zgodne inaczej).

bash(odpowiedź GNU na powłokę Korna) jest w rzeczywistości jedyną powłoką typu open source (i można powiedzieć, że obecnie jest utrzymywana, ponieważ inne są generalnie oparte na ksh88, który nie otrzymał żadnej nowej funkcji od lat 90.), który został certyfikowany jako zgodność z POSIX sh(jako część certyfikacji macOS).

Kiedy piszesz skrypt za pomocą #! /bin/sh -she-bang, powinieneś użyć standardowej shskładni (i powinieneś również użyć standardowej składni narzędzi używanych w tym skrypcie, jeśli chcesz być przenośny, to nie tylko powłoka jest zaangażowana podczas interpretacji powłoki skrypt), to nie ma znaczenia, jaka implementacja tego standardowego shinterpretera składni jest używana ( ksh, bash...).

Nie ma znaczenia, że ​​te powłoki mają rozszerzenia ponad standard, o ile ich nie używasz. To tak, jakby pisać kod C, o ile piszesz standardowy kod C i nie używasz rozszerzeń jednego kompilatora (podobnego gcc) lub drugiego, kod powinien kompilować się OK bez względu na implementację kompilatora, pod warunkiem, że kompilator jest zgodny.

Tutaj z #! /bin/shshe-bang, głównym problemem byłyby systemy, w których /bin/shjest Bourne shell, że na przykład nie obsługuje standardowe funkcje, takie jak $((1+1)), $(cmd), ${var#pattern}... W takim przypadku konieczne może być obejścia takich jak:

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

Nawiasem mówiąc, Ubuntu /bin/shnie bashjest domyślnie. Obecnie jest dashto powłoka oparta na NetBSD sh, sama oparta na powłoce Almquist, która jest w większości zgodna z POSIX, z wyjątkiem tego, że nie obsługuje znaków wielobajtowych. W Ubuntu i innych systemach opartych na Debianie możesz wybierać pomiędzy bashi dashza /bin/shpomocą 4dpkg-reconfigure dash ) . skrypty dostarczane z Debianem powinny działać tak samo w obu powłokach, ponieważ są zapisane w standardzie polityki Debiana (nadzbiór standardu POSIX). Prawdopodobnie znajdziesz również pracować OK „s emulacji lub (prawdopodobnie nie , ani które nie mają polecenie wbudowane (wymagane przez politykę Debiana ale nie POSIX)).shzshshboshksh93yashlocal

Wszystkie systemy w unix.stackexchange.com mają sh gdzieś POSIX . Większość z nich ma /bin/sh(możesz znaleźć bardzo rzadkie, które nie mają /binkatalogu, ale prawdopodobnie nie przejmujesz się tym), i na ogół jest to shinterpreter POSIX (aw rzadkich przypadkach (niestandardowa) powłoka Bourne'a ).

Ale shjest to jedyny plik wykonywalny interpretera powłoki, który z pewnością znajdziesz w systemie. W przypadku innych powłok możesz być pewien, że będą miały macOS, Cygwin i większość dystrybucji GNU / Linux bash. Systemy operacyjne wywodzące się z SYSV (Solaris, AIX ...) zazwyczaj mają ksh88, prawdopodobnie ksh93. OpenBSD, MirOS będzie miał pochodną pdksh. macOS będzie miał zsh. Ale z tego nie będzie żadnej gwarancji. Nie ma gwarancji, że bashani żadna z tych innych powłok nie zostanie zainstalowana w /bininnym miejscu (zwykle znajduje się /usr/local/binna BSD, gdy jest instalowana). I oczywiście nie ma gwarancji wersji powłoki, która zostanie zainstalowana.

Zauważ, że #! /path/to/executablenie jest to konwencja , jest to cecha wszystkich jąder uniksopodobnych ( wprowadzonych na początku lat 80. przez Dennisa Ritchiego ), która umożliwia wykonywanie dowolnych plików poprzez określenie ścieżki interpretera w pierwszym wierszu, zaczynając od #!. Może to być dowolny plik wykonywalny.

Po uruchomieniu pliku, którego pierwsza linia rozpoczyna się #! /some/file some-optional-argjądro kończy się wykonaniem /some/filez some-optional-arg, ścieżki skryptu i oryginalnych argumentów jako argumenty. Możesz zrobić ten pierwszy wiersz, #! /bin/echo testaby zobaczyć, co się dzieje:

$ ./myscript foo
test ./myscript foo

Kiedy używasz /bin/sh -zamiast /bin/echo test, jądro wykonuje /bin/sh - ./myscript foo, shinterpretuje kod zawartości zapisany w nim myscripti ignoruje ten pierwszy wiersz jako komentarz (zaczyna się od #).


¹ Prawdopodobnie jedynym obecnie systemem, w którym ktokolwiek z nas natknie się na system /bin/shoparty na powłoce Bourne'a, jest Solaris 10. Solaris jest jednym z niewielu uników, które zdecydowały się zachować tam powłokę Bourne'a ze względu na kompatybilność wsteczną ( shjęzyk POSIX nie jest w pełni wstecznie kompatybilny z powłoką Bourne'a) i (przynajmniej dla wdrożeń na komputery stacjonarne i pełne serwery) mają POSIX shgdzie indziej (w /usr/xpg4/bin/sh, na podstawie ksh88), ale zmieniło się to w Solarisie 11, gdzie /bin/shjest teraz ksh93. Pozostałe są w większości nieczynne.

² MacOS / X stosowany się , a później zmieniła się . Używanie go jako implementacji POSIX nie jest głównym celem . Jego trybem jest przede wszystkim możliwość osadzania lub wywoływania ( ) kodu POSIX w skryptach/bin/shzshbashzshshshsourceshzsh

³ Ostatnio @schily rozszerzył powłokę OpenSolaris (bazującą na powłoce SVR4, opartą na powłoce Bourne'a), aby stała się zgodna z POSIX, boshale nie wiem, czy jest ona używana w żadnym systemie. Dzięki ksh88temu jest to druga powłoka zgodna z POSIX, oparta na kodzie powłoki Bourne'a

4 W starszych wersjach można również użyć mkshlub jego większej lkshinkarnacji POSIX . To jest powłoka MirOS (wcześniej MirBSD) oparta na pdksh, sama oparta na powłoce Forsyth (kolejna reimplementacja powłoki Bourne))

Stéphane Chazelas
źródło
Drobna rzecz (o środkowej odpowiedzi kodu powłoki): Nie powinieneś używać zaraz exec sh "$0" "$@"po ustawieniu PATH? To powinno odebrać shz właściwego miejsca, pomyślałem.
Kusalananda
1
@Kusalananda, to powinno działać, ale jest bardziej ryzykowne, ponieważ moglibyśmy skończyć w nieskończonej pętli, jeśli coś jest nie tak (jak sh z niewłaściwymi uprawnieniami, zmodyfikowano getconf ...). Zresztą reszta jest specyficzna dla Solaris 10, więc moglibyśmy także zakodować wszystko, łącznie z zawartością $PATH.
Stéphane Chazelas,
Wszelkie cytaty dla OSX używającego ksh jako powłoki POSIX. Jego domyślną powłoką był tcsh, ale nie pamiętam, że bash nie był używany, zwłaszcza że Korn Shell nie był open source, dopóki nie wyszedł OSX
151019
1
@ Mark, nie powiedziałem, że OSX kiedykolwiek używał ksh. Powiedziałem, że to był zsh i zmienili się na bash (specjalna wersja bash).
Stéphane Chazelas
1
@fpmurphy, jeśli spojrzysz na wczesne wersje, bash był już po stronie ksh wszędzie tam, gdzie ksh nie był kompatybilny z powłoką Bourne'a. Podczas gdy trzeba było czekać do bash2, aby przejść do tego samego poziomu funkcji co ksh88, bash początkowo miał już kilka rozszerzeń ksh, takich jak $(...)tryby emacs / vi, rozszerzenia tyldy / nawiasów klamrowych (te początkowo z csh), fc, skład, alias , składnia funkcji w stylu ksh ...
Stéphane Chazelas
8

Tak, możesz użyć #!/bin/shw skrypcie, ponieważ /bin/shjest (mam nadzieję) przewidziany w takich systemach, zwykle za pośrednictwem linku, który sprawia, że bashzachowujesz się (mniej więcej) tak, jak shby to zrobił. Oto na przykład system Centos7, który prowadzi shdo bash:

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

Możesz także użyć, #!/bin/bashjeśli piszesz bashskrypt tylko dla tego systemu i chcesz korzystać z bashfunkcji. Jednak takie skrypty będą miały problemy z przenośnością, na przykład na OpenBSD, gdzie bashjest instalowany tylko wtedy, gdy administrator z trudem go zainstaluje (nie robię), a następnie jest instalowany /usr/local/bin/bash, a nie /bin/bash. #!/bin/shSkrypt ściśle POSIX powinien być bardziej przenośny.

gałązka
źródło
Uwaga: „Po wywołaniu jako sh, Bash przechodzi do trybu POSIX po odczytaniu plików startowych.” - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
glenn jackman
2
Kiedy piszę skrypty dla serwerów RHEL w mojej pracy, używam ich #!/bin/bashdokładnie, aby móc korzystać z funkcji innych niż POSIX.
Monty Harder
@MontyHarder IIRC na RHEL /bin/shto dowiązanie symboliczne bash, czy to prawda? Ale wiem na pewno o CentOS.
Sergiy Kolodyazhnyy
1
@SergiyKolodyazhnyy Tak, na serwerze RHEL, który właśnie sprawdziłem, jest to dowiązanie symboliczne bash. Plik binarny wie, jaką nazwę użyto do wywołania go, a kiedy się nazywa sh, działa jak oldschoolowy Bourne sh.
Monty Harder
6

Zapytałeś

czy poprawne jest umieszczenie komentarza #! / bin / sh w skryptach powłoki napisanych w dystrybucjach ubuntu?

Odpowiedź zależy od tego, co napiszesz w skrypcie powłoki.

  • Jeśli ściśle używasz przenośnych skryptów zgodnych z POSIX i nie używasz żadnych poleceń specyficznych dla bash, możesz tego użyć /bin/sh.

  • Jeśli wiesz, że kiedykolwiek używasz skryptu tylko na maszynie z bash i chcesz użyć składni specyficznej dla bash, powinieneś użyć/bin/bash

  • Jeśli chcesz mieć pewność, że skrypt będzie działał na asortymencie maszyn unixowych, powinieneś używać tylko składni zgodnej z POSIX, i/bin/sh

  • Jeśli regularnie używać innej powłoki (np ksh , zsh lub tcsh ), a chcesz używać tej składni w skrypcie, to należy użyć odpowiedniego tłumacza (jak /bin/ksh93, /bin/zshlub /bin/tcsh)

Stobor
źródło
3

„#!” komentarz nie zawsze używa /bin/bashlub /bin/sh. Podaje tylko, czym powinien być interpreter, nie tylko w przypadku skryptów powłoki. Na przykład moje skrypty python zwykle zaczynają się od #!/usr/bin/env python.

Teraz różnica między #!/bin/shi #!/bin/bashjest taka, że /bin/shnie zawsze jest to dowiązanie symboliczne /bin/bash. Często, ale nie zawsze. Ubuntu jest tutaj godnym uwagi wyjątkiem. Widziałem skrypty działające poprawnie na CentOS, ale nie działające na Ubuntu, ponieważ autor używał składni specyficznej dla bash #!/bin/sh.

aragaer
źródło
1

Przepraszamy za nalewanie zimnej wody wszystkim wspaniałym odpowiedziom, które mówią, że /bin/shjest obecny we wszystkich systemach uniksowych - jest obecny, z wyjątkiem najczęściej używanego systemu Unix wszechczasów: Androida.

Android ma swoją powłokę /system/bin/shi zwykle nie ma możliwości utworzenia /bin/shłącza, nawet w systemie zrootowanym (z powodu sposobu, w jaki system jest zablokowany za pomocą zestawów ograniczających selinux i zdolności (7)).

Dla tych, którzy powiedzą, że Android nie jest zgodny z POSIX: nie ma też większości dystrybucji Linuksa i BSD. A istnienie /bin/shtej ścieżki nie jest wymagane przez standard :

Wnioski należy pamiętać, że średnia PATHdla powłoki nie można przyjąć, aby być /bin/shalbo /usr/bin/shi powinna być określona przez Odczytywanie PATHzwracane przez getconf PATH, zapewniając, że zwracany jest ścieżka bezwzględna ścieżka a nie powłoki wbudowanej.

mosvy
źródło
Chociaż wszystkie systemy, które próbują być zgodne z POSIX, zawierają liczne błędy zgodności (w tym certyfikowane), Android (i większość innych systemów wbudowanych, takich jak router lub żarówka OS) nie zamierzają być zgodne z POSIX. Android jest tutaj nie na temat, chyba że chodzi o interfejs POSIX.
Stéphane Chazelas,
@Christopher, który getconf? Na przykład w systemie Solaris 11.4 /usr/bin? Jeden w /usr/xpg4/bin(dla zgodności z SUSv2), Jeden w /usr/xpg6/bin(dla zgodności z SUSv3)? /usr/xpg7/bin(dla SUSv4)?
Stéphane Chazelas,
@ StéphaneChazelas, jeśli jesteśmy gotowi osądzać intencje, myślę, że mogę z łatwością wykopać kilka słów Linusa Torvaldsa lub Theo de Raadta, że ​​nie przejmują się zbytnio POSIXem ;-) A większość systemów osadzonych opiera się na Linuksie + busybox, który nie jest mniej zgodny z POSIX niż typowy system uniksowy. I a) Android nie jest tak naprawdę systemem „wbudowanym” oraz b) System Android może być zgodny z POSIX- /bin/sh
em
1
@mosvy, to, co mówisz, jest w większości prawdą. Ale Torvalds może mówić tylko za jądrem Linuksa. Chet Ramey dba o zgodność z POSIX dla bash, RedHat dba o zgodność z POSIX (sponsorują grupę Austin i siedzą na spotkaniach grupy, utrzymują dużo oprogramowania GNU). Chodzi o to, że POSIX jest jedynym standardem, na który patrzy większość systemów uniksowych. Użytkownikom zależy na zgodności z POSIX, ponieważ ułatwia to przenoszenie oprogramowania na różne systemy. To nie jest idealne, ale lepsze niż nic. Android ma własny programistyczny interfejs API, POSIX nie jest tak naprawdę problemem.
Stéphane Chazelas,