nagłówki skryptu powłoki (#! / bin / sh vs #! / bin / csh)


92

Dlaczego wszystkie pliki skryptów zaczynają się od

#!/bin/sh

lub z

#!/bin/csh

Czy to jest wymagane? Jaki jest tego cel? Jaka jest różnica między nimi?


1
W przypadku skryptu csh powinieneś użyć #!/bin/csh -f; -fmówi powłoce nie pozyskać użytkownika .logini .cshrc, co sprawia, że szybciej uruchomić skrypt i unika zależności od ustawień użytkownika. (Lub jeszcze lepiej, nie pisz skryptów csh.) Nie używaj -fdo skryptów sh lub bash; nie ma tego samego znaczenia.
Keith Thompson

Odpowiedzi:


99

Jest to znane jako Shebang:

http://en.wikipedia.org/wiki/Shebang_(Unix)

#! interpreter [opcjonalny-arg]

Shebang ma znaczenie tylko wtedy, gdy skrypt ma pozwolenie na wykonanie (np. Chmod u + x script.sh).

Kiedy powłoka wykonuje skrypt, użyje określonego interpretera.

Przykład:

#!/bin/bash
# file: foo.sh
echo 1

$ chmod u+x foo.sh
$ ./foo.sh
  1

@Kolob Canyon nie musisz, ale może pomóc niektórym redaktorom w podświetlaniu składni (chociaż zwykle są inne sposoby na osiągnięcie tego samego): unix.stackexchange.com/a/88730/193985
Braham Snyder

42

#!Linia informuje jądro (w szczególności realizacji execvewywołania systemowego), że ten program jest napisany w języku interpretowanym; bezwzględna nazwa ścieżki, która następuje, identyfikuje interpretera. Programy skompilowane do kodu maszynowego zaczynają się od innej sekwencji bajtów - w większości nowoczesnych Uniksów, 7f 45 4c 46( ^?ELF), która je identyfikuje.

Możesz umieścić bezwzględną ścieżkę do dowolnego programu po tagu #!, o ile sam ten program nie jest #!skryptem. Jądro przepisuje wywołanie

./script arg1 arg2 arg3 ...

gdzie ./scriptzaczyna się, powiedzmy, #! /usr/bin/perltak, jakby wiersz poleceń faktycznie istniał

/usr/bin/perl ./script arg1 arg2 arg3

Lub, jak widziałeś, możesz użyć #! /bin/shdo napisania skryptu, który ma być interpretowany przez sh.

#!Linii są przetwarzane tylko wtedy, gdy bezpośrednio wywołać skrypt ( ./scriptw linii poleceń); plik musi być również wykonywalny ( chmod +x script). Jeśli nie linia nie jest konieczne (i będą ignorowane, jeśli jest obecny), a plik nie musi być wykonywalny. Punkt z tej funkcji jest umożliwienie Ci bezpośrednio invoke programów interpretowany języków bez konieczności znać język, jakim są napisane. (Do - będzie można odkryć, że bardzo wiele programów akcji są w rzeczywistości przy użyciu tej funkcji.)sh ./script#!grep '^#!' /usr/bin/*

Oto kilka zasad korzystania z tej funkcji:

  • #!Muszą być dwie bardzo pierwsze bajty w pliku. W szczególności plik musi być kodowany zgodnie z ASCII (np. UTF-8 będzie działać, ale UTF-16 nie) i nie może zaczynać się od „znaku kolejności bajtów”, w przeciwnym razie jądro nie rozpozna go jako #!scenariusz.
  • Ścieżka po #!musi być ścieżką bezwzględną (zaczyna się od /). Nie może zawierać znaków spacji, tabulacji ani nowej linii.
  • Jest to dobry styl, ale nie jest to wymagane, aby wstawić spację między #!i /. Nie umieszczaj tam więcej niż jednej spacji.
  • Nie możesz umieścić zmiennych powłoki w #!linii, nie zostaną one rozwinięte.
  • Możesz umieścić jeden argument wiersza poleceń po ścieżce bezwzględnej, oddzielony od niej pojedynczą spacją. Podobnie jak ścieżka bezwzględna, ten argument nie może zawierać znaków spacji, tabulacji ani nowego wiersza. Czasami jest to konieczne, aby rzeczy działały ( #! /usr/bin/awk -f), czasami jest to po prostu przydatne ( #! /usr/bin/perl -Tw). Niestety nie możesz umieścić dwóch lub więcej argumentów po ścieżce bezwzględnej.
  • Niektórzy ludzie powiedzą ci, żebyś używał #! /usr/bin/env interpreterzamiast #! /absolute/path/to/interpreter. To prawie zawsze błąd. Sprawia, że ​​zachowanie programu zależy od $PATHzmiennej użytkownika, który wywołuje skrypt. I nie wszystkie systemy są envna pierwszym miejscu.
  • Programy, które potrzebują setuidlub setgidprzywilejów, nie mogą ich używać #!; muszą być skompilowane do kodu maszynowego. (Jeśli nie wiesz, co to setuidjest, nie martw się tym).

Odnośnie csh, odnosi się to shmniej więcej do tego, co Nutrimat Advanced Tea Substitute ma do herbaty. Ma (a raczej miał; współczesne implementacje shdogoniły) szereg zalet w porównaniu shz interaktywnym użyciem, ale używanie go (lub jego następcy tcsh) do tworzenia skryptów jest prawie zawsze błędem . Jeśli nie znasz ogólnie skryptów powłoki, zdecydowanie zalecam zignorowanie tego i skupienie się na sh. Jeśli używasz cshkrewnego jako powłoki logowania, przełącz na bashlub zsh, aby interaktywny język poleceń był taki sam, jak język skryptowy, którego się uczysz.


Najnowsze wersje Linuksa pozwalają, aby określony interpreter był skryptem. Powszechną praktyką jest pomijanie spacji po #!; bez komentarza, czy to dobry styl. Zobacz to pytanie i moją odpowiedź, aby omówić zalety i wady #!/usr/bin/envwłamania.
Keith Thompson

@KeithThompson Mam wrażenie, że Linux jest jedynym powszechnym wariantem Uniksa, który pozwala interpreterowi być skryptem, więc nadal nie można na nim polegać. Odkąd to napisałem, sam spotkałem się z sytuacją, w której #!/usr/bin/envbyła Właściwa Rzecz, ale pozostaje moim zdaniem, że prawie zawsze jest to zły pomysł.
zwol

4

Określa, jakiej powłoki (interpretera poleceń) używasz do interpretowania / uruchamiania skryptu. Każda powłoka różni się nieco sposobem interakcji z użytkownikiem i wykonywania skryptów (programów).

Kiedy wpisujesz polecenie w linii poleceń systemu Unix, wchodzisz w interakcję z powłoką.

Np. #!/bin/cshOdnosi się do powłoki C, powłoki /bin/tcsht, powłoki /bin/bashbash itp.

Możesz powiedzieć, której powłoki interaktywnej używasz

 echo $SHELL

polecenie lub alternatywnie

 env | grep -i shell

Możesz zmienić powłokę poleceń za pomocą chshpolecenia.

Każdy ma nieco inny zestaw poleceń i sposób przypisywania zmiennych oraz własny zestaw konstrukcji programistycznych. Na przykład instrukcja if-else z bash wygląda inaczej niż ta w powłoce C.

Ta strona może być interesująca, ponieważ "tłumaczy" pomiędzy poleceniami / składnią bash i tcsh.

Użycie dyrektywy w skrypcie powłoki umożliwia uruchamianie programów przy użyciu innej powłoki. Na przykład używam tcshpowłoki interaktywnie, ale często uruchamiam skrypty bash za pomocą / bin / bash w pliku skryptu.

Na bok:

Ta koncepcja rozciąga się również na inne skrypty. Na przykład, jeśli programujesz w Pythonie, umieścisz

 #!/usr/bin/python

u góry programu w Pythonie


Czy jest to wymagane? Skąd mam wiedzieć, której powłoki naprawdę używam?
One Two Three

Więc jeśli piszę skrypty dla kogoś do użycia na ich komputerze i nie wiem, jakiej powłoki używają. (Ta osoba niestety nie ma pojęcia o tych rzeczach, więc jedyne, co może zrobić, to uruchomić skrypt bez zmiany rzeczy). Czy mogę zrobić coś takiego #! $SHELL? Czy to umieściłoby właściwą muszlę w Shebangu?
One Two Three

1
@OneTwoThree Większość systemów ma standardowe powłoki, jeśli napiszesz skrypt bash lub csh, wszystko będzie dobrze. Nie ma znaczenia, jakiej powłoki używają interaktywnie , to jest piękno np !#/bin/bash. Dyrektywy. Informuje system, jakiej powłoki należy użyć do wykonania skryptu powłoki.
Levon

Wartość $SHELLniekoniecznie mówi ci, z której powłoki aktualnie korzystasz; zwykle mówi ci o twojej domyślnej powłoce. zestawy tcsh $versioni $tcsh; zestawy bash $BASH_VERSION. Nie wszystkie muszle muszą mieć podobne mechanizmy.
Keith Thompson

1
@OneTwoThree: #!Linia musi pasować do składni skryptu, a nie do powłoki interaktywnej używanej przez każdego, kto uruchamia skrypt.
Keith Thompson
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.