Dlaczego musisz umieścić #! / Bin / bash na początku pliku skryptu?

484

Zrobiłem Bash skryptów przed i wszystko Ran grzywny bez #!/bin/bashpoczątku.

Po co to wkładać? Czy byłoby inaczej?

Jak się wymawiasz #? Wiem, że !wymawia się to jako „huk”.

Jak #!wymawia się?

węzeł ninja
źródło
8
Nie musisz i nie powinieneś, chyba że nie masz wyboru. Użyj „#! / Bin / sh”, gdy możesz i poznaj różnicę między powłoką (POSIX) a bash. Nadejdzie dzień, zanim twoje CV wzrośnie o wiele dłużej, gdy znajdziesz się w systemie z inną powłoką i nadal chcesz, aby twoje skrypty działały.
Jens
50
Wymawia się „Hash-Bang” lub „She-Bang”.
Beachhouse
22
Myślę, że warto zauważyć, że jest to wykonywane tylko wtedy, gdy uruchamiasz skrypt jako plik wykonywalny. Więc jeśli ustawisz flagę wykonywalną, a następnie wpiszesz ./yourscript.extension, na przykład, ./helloworld.pylub ./helloworld.shbędzie szukał interpretera w tym górnym wierszu, który byłby #!/bin/pythonlub !#/bin/bash, podczas gdy podczas wykonywania skryptu python helloworld.py, pierwsza linia nie będzie obserwowana, ponieważ jest skomentowana na zewnątrz. Jest to więc specjalna sekwencja dla powłoki / jądra.
JFA
@JFA występuje zmiana sekwencji między bash a pythonem, gdy używasz! # Dla python i #! za bash?
AAI
1
@AjeyaAnand i nie, to był błąd, dobry haczyk
JFA

Odpowiedzi:

425

Jest to konwencja, więc powłoka * nix wie, jakiego rodzaju tłumacza należy uruchomić.

Na przykład starsze wersje ATT miały domyślnie sh (powłoka Bourne'a), a starsze wersje BSD domyślnie csh (powłoka C).

Nawet dzisiaj (gdzie większość systemów uruchamia bash, „Bourne Again Shell” ), skrypty mogą być w bash, python, perl, ruby, PHP itp., Na przykład, możesz zobaczyć #!/bin/perllub #!/bin/perl5.

PS: Wykrzyknik ( !) jest pieszczotliwie nazywany „hukiem” . Symbol komentarza powłoki ( #) jest czasem nazywany „hash” .

PPS: Pamiętaj - w * nix kojarzenie sufiksu z typem pliku jest jedynie konwencją , a nie „regułą” . Plik wykonywalny może być programem binarnym, dowolnym z miliona typów skryptów i innymi rzeczami. Stąd potrzeba #!/bin/bash.

paulsm4
źródło
1
Dowiedziałem się o czymś innym przydatnym, $ #. Jak to się nazywa?
węzeł ninja
91
Shebang nie jest konwencją powłoki , jest interpretowany przez jądro podczas obsługi execve(2)syscall; więc shebang jest konwencją jądra , a nie powłoką.
Basile Starynkevitch
10
Pomaga także niektórym redaktorom, takim jak Vim, określić język podświetlania składni, jeśli plik nie ma rozszerzenia. Bez shebang Vim wyświetli skrypt bash tak samo jak zwykły plik tekstowy.
Aaron Blenkush,
1
Zastanawiam się, czy trzeba dodawać #!/bin/shrzeczy takie jak .profilei rzeczy działające pod obciążeniem
Kanion Kolob
5
Więc ... hash-bang-slash-bin-slash-bash ?
Bernat
134

Mówiąc ściślej, shebang #! , gdy jest to pierwsze dwa bajty pliku wykonywalnego ( x trybu ), jest interpretowany przez wywołanie systemowe execve (2) (które wykonują programy). Ale specyfikacja POSIX dlaexecve nie wspomina o shebang.

Po nim musi znajdować się ścieżka do pliku wykonywalnego interpretera (który BTW może nawet być względny, ale najczęściej jest bezwzględny).

Fajną sztuczką (lub być może nie taką ), aby znaleźć tłumacza (np. python) U użytkownika, $PATHjest użycie envprogramu (zawsze /usr/bin/envna wszystkich systemach Linux), takich jak np.

 #!/usr/bin/env python

Dowolny plik wykonywalny ELF może być tłumaczem. Możesz nawet użyć #!/bin/catlub #!/bin/truejeśli chcesz! (ale byłoby to często bezużyteczne)

Basile Starynkevitch
źródło
8
Zobacz to pytanie, aby omówić #!/usr/bin/envwłamanie.
Keith Thompson,
jeśli chcę przekazać argument do Pythona, jak to zrobić, to chcę wykonać #!/usr/bin/env bash -x. Jak mogę to zrobić ?
indianwebdevil
to proste, ja sam to znalazłem, po prostu dodaj param później#!/usr/bin/env bash -x
indianwebdevil
bashjest prawie zawsze, /bin/bashwięc twój shebang powinien być#!/bin/bash -x
Basile Starynkevitch
49

To się nazywa shebang . W unix-speak # nazywa się sharp (jak w muzyce) lub hash (jak hashtagi na Twitterze), i! nazywa się bang. (Możesz faktycznie odwołać się do poprzedniego polecenia powłoki za pomocą !!, zwanego bang-bang). Więc kiedy są razem, otrzymujesz haSH-BANG lub shebang.

Część po #! mówi Unixowi, jakiego programu użyć, aby go uruchomić. Jeśli nie zostanie określony, spróbuje użyć bash (lub sh, zsh, lub cokolwiek to jest zmienna $ SHELL), ale jeśli tam jest, użyje tego programu. Dodatkowo # jest komentarzem w większości języków, więc wiersz jest ignorowany przy kolejnym wykonaniu.

austin1howard
źródło
2
Jeśli jestem już w bashu, czy uruchamia inną instancję basha, jeśli zobaczy #! / Bin / bash? Co jeśli jestem już w bashu i pominę to? Czy jest jakaś różnica?
węzeł ninja
2
@javascriptninja w obu przypadkach uruchamia nową powłokę bash. W przypadku bash tak naprawdę nie ma różnicy, o ile już używasz bash. Szanghaj naprawdę ma znaczenie tylko wtedy, gdy (a) musisz uruchomić coś, co nie jest tylko powłoką, np. Python lub perl, lub (b) nie używasz powłoki bash (tj. Używasz zsh), ale musisz uruchomić coś, co wymaga bashu.
austin1howard
Uważam jednak, że dobrą praktyką jest dołączanie shebang, aby ktoś czytający kod wiedział, co się dzieje.
austin1howard
2
Źle: execve(2)syscall nie używa $SHELLzmiennej To jądro interpretuje shebang.
Basile Starynkevitch
1
@BasileStarynkevitch, który jest poprawny, moduł ładujący elf w jądrze interpretuje shebang. Oświadczyłem, że $ SHELL byłby użyty, gdyby nie podano shebang.
austin1howard
19

Shebang jest dyrektywą do ładowarki w użyciu program, który jest określony po #!jako tłumacza dla danego pliku podczas próby, aby go wykonać. Tak więc, jeśli spróbujesz uruchomić plik o nazwie, foo.shktóry ma #!/bin/bashna górze, faktycznie uruchomione polecenie to /bin/bash foo.sh. Jest to elastyczny sposób używania różnych tłumaczy dla różnych programów. Jest to coś zaimplementowanego na poziomie systemu, a interfejsem API na poziomie użytkownika jest konwencja shebang.

Warto również wiedzieć, że shebang jest liczbą magiczną - czytelną dla człowieka, która identyfikuje plik jako skrypt dla danego tłumacza.

Chodzi o to, że „działa” nawet bez shebang, tylko dlatego, że dany program jest skryptem powłoki napisanym dla tej samej powłoki co ta, której używasz. Na przykład możesz bardzo dobrze napisać plik javascript, a następnie umieścić #! /usr/bin/js(lub coś podobnego), aby mieć „skrypt powłoki” javascript.

Noufal Ibrahim
źródło
18

System operacyjny przyjmuje domyślną powłokę do uruchomienia skryptu powłoki. więc wspominając o ścieżce powłoki na początku skryptu, prosisz system operacyjny o użycie tej konkretnej powłoki. Jest także przydatny do przenoszenia .

Balaswamy Vaddeman
źródło
15

Każda dystrybucja ma domyślną powłokę. Bash jest domyślny w większości systemów. Jeśli zdarzy ci się pracować w systemie, który ma inną domyślną powłokę, skrypty mogą nie działać zgodnie z przeznaczeniem, jeśli są napisane specjalnie dla Bash.

Bash ewoluował przez lata, biorąc kod z kshi sh.

Dodanie #!/bin/bashjako pierwszego wiersza skryptu informuje system operacyjny o wywołaniu określonego shellpolecenia w celu wykonania poleceń podanych w skrypcie.

#! jest często określany jako „hash-bang”, „she-bang” lub „sha-bang”.

jaypal singh
źródło
9

To się nazywa shebang . Składa się ze znaku liczbowego i znaku wykrzyknika (#!), Po którym następuje pełna ścieżka do interpretera, takiego jak / bin / bash. Wszystkie skrypty w systemach UNIX i Linux są wykonywane przy użyciu interpretera określonego w pierwszym wierszu.

Uday Sawant
źródło
0

Może być przydatny dla kogoś, kto używa innego systemu, który nie ma tej biblioteki łatwo dostępnej. Jeśli nie jest to zadeklarowane i masz w skrypcie pewne funkcje, które nie są obsługiwane przez ten system, powinieneś zadeklarować # / bin / bash. Natrafiłem na ten problem wcześniej w pracy, a teraz po prostu włączam go jako praktykę.

Beardy
źródło