W bash
lub sh
chyba wszystko, co zaczyna się od, #
jest komentarzem .
Ale w bash
skryptach piszemy:
#!/bin/bash
A w skryptach Python jest:
#!/bin/python
Czy to oznacza, że #
sam w sobie jest komentarzem, a #!
nie jest?
W bash
lub sh
chyba wszystko, co zaczyna się od, #
jest komentarzem .
Ale w bash
skryptach piszemy:
#!/bin/bash
A w skryptach Python jest:
#!/bin/python
Czy to oznacza, że #
sam w sobie jest komentarzem, a #!
nie jest?
Odpowiedzi:
#!
Linia jest używana przed prowadzony jest skrypt, a następnie ignorowane , gdy skrypt jest uruchamiany.Pytasz, jaka jest różnica między linią shebang a zwykłym komentarzem.
Linia zaczynająca się od #!
jest tak samo komentarzem jak każda inna linia zaczynająca się od #
. Dzieje się tak, jeśli #!
jest to pierwszy wiersz pliku lub gdziekolwiek indziej. #!/bin/sh
ma efekt , ale nie jest odczytywany przez samego tłumacza .
#
nie jest komentarzem we wszystkich językach programowania, ale, jak wiecie, jest komentarzem w powłokach w stylu Bourne'a, w tym sh
i bash
(a także w większości takich powłok csh
). To także komentarz w Pythonie . Jest to komentarz w wielu plikach konfiguracyjnych, które wcale nie są skryptami (jak /etc/fstab
).
Załóżmy, że skrypt powłoki zaczyna się od #!/bin/sh
. To jest komentarz, a tłumacz (powłoka) ignoruje wszystko w wierszu po #
znaku.
Celem #!
linii nie jest udzielanie informacji tłumaczowi. Celem tego #!
wiersza jest poinformowanie systemu operacyjnego (lub innego procesu uruchamiającego interpreter), co ma być używane jako interpreter .
Jeśli skrypt zostanie wywołany jako plik wykonywalny, na przykład przez uruchomienie ./script.sh
, system przejdzie do pierwszego wiersza, aby sprawdzić, czy zaczyna się od #!
, po którym następuje zero lub więcej spacji, a następnie polecenie. Jeśli tak, uruchamia to polecenie z nazwą skryptu jako argumentu. W tym przykładzie działa /bin/sh script.sh
(lub technicznie /bin/sh ./script.sh
).
Jeśli skrypt zostanie wywołany przez jawne wywołanie interpretera, #!
linia nigdy nie zostanie sprawdzona. Więc jeśli uruchomisz sh script.sh
, pierwsza linia nie ma wpływu. Jeśli script2.sh
pierwszym wierszem jest #!/usr/games/nibbles
, uruchomienie sh script2.sh
nie spróbuje otworzyć skryptu w nibbles
(ale ./script2.sh
zrobi).
Zauważysz, że w żadnym przypadku rozszerzenie skryptu ( .sh
), jeśli takie posiada, nie wpływa na sposób jego działania. W systemie uniksowym zwykle nie wpływa to na sposób uruchamiania skryptu. W niektórych innych systemach, takich jak Windows, #!
linia shebang może być całkowicie ignorowana przez system, a rozszerzenie może określać, co uruchamia skrypty. (Nie oznacza to, że musisz podawać rozszerzenia skryptów, ale jest to jeden z powodów, dla których tak robisz, powinny być poprawne).
#!
został wybrany, aby służyć temu celowi właśnie dlatego , że#
zaczyna się komentarz. #!
Linia jest w systemie, a nie tłumacz, i powinno być ignorowane przez interpreter.
Ty (pierwotnie) powiedział użyć #!/bin/sh
dla bash
skryptów. Powinieneś to zrobić tylko wtedy, gdy skrypt nie wymaga żadnego z bash
rozszerzeń - sh
musi być w stanie uruchomić skrypt. sh
nie zawsze jest dowiązaniem symbolicznym do bash
. Często, w tym na wszystkich ostatnio zdalnych systemach Debian i Ubuntu , sh
jest dowiązaniem symbolicznym dash
.
Powiedziałeś także (w pierwszej wersji swojego pytania, przed edycją), że uruchamiasz skrypty Pythona #!/bin/sh read by the interpretor
. Jeśli masz na myśli dosłownie, zdecydowanie powinieneś przestać to robić. Jeśli hello.py
zaczyna się od tej linii, uruchamianie ./hello.py
wykonuje:
/bin/sh read by the interpretor hello.py
/bin/sh
spróbuje wykonać skrypt o nazwie read
(ze by the interpretor hello.py
swoimi argumentami), read
(miejmy nadzieję) nie zostanie znaleziony, a twój skrypt w Pythonie nigdy nie będzie widoczny dla interpretera Pythona.
Jeśli popełniasz ten błąd, ale nie mam problemu, który opisuję, prawdopodobnie python hello.py
wywołujesz skrypty Pythona, jawnie określając interpreter (np. ), Co powoduje zignorowanie pierwszej linii. Kiedy dystrybuujesz swoje skrypty innym osobom lub używasz ich przez długi czas później, może nie być jasne, że jest to konieczne do ich działania. Najlepiej je teraz naprawić. Lub przynajmniej całkowicie usuń pierwszy wiersz, aby w przypadku niepowodzenia uruchomienia ./
komunikat o błędzie miał sens.
W przypadku skryptów w języku Python, jeśli wiesz, gdzie jest (lub będzie) interpreter języka Python, możesz napisać #!
wiersz w ten sam sposób:
#!/usr/bin/python
Lub, jeśli jest to skrypt w języku Python 3, należy określić python3
, ponieważ python
prawie zawsze jest to język Python 2 :
#!/usr/bin/python3
Problem polega jednak na tym, że chociaż /bin/sh
powinien istnieć zawsze i /bin/bash
prawie zawsze istnieje w systemach bash
z systemem operacyjnym, Python może istnieć w różnych miejscach.
Dlatego wielu programistów Python używa tego zamiast tego:
#!/usr/bin/env python
(Lub #!/usr/bin/env python3
dla Python 3.)
To sprawia, że skrypt polega na env
byciu w „właściwym miejscu” zamiast na python
byciu we właściwym miejscu. To dobrze, ponieważ:
env
prawie zawsze znajduje się w /usr/bin
.python
powinien zostać uruchomiony, jest ten, który pojawia się jako pierwszy w PATH
. Począwszy hello.py
od #!/usr/bin/env python
make ./hello.py
run /usr/bin/env python hello.py
, który jest (praktycznie) równoważny z bieganiem python hello.py
.Nie możesz użyć #!python
tego, że:
/
).python
w bieżącym katalogu . Przeszukiwanie ścieżki, gdy polecenie nie zawiera ukośnika, jest specyficznym zachowaniem powłoki.Czasami Python lub inny skrypt, który nie jest skryptem powłoki, będzie miał linię shebang zaczynającą się od miejsca, w #!/bin/sh ...
którym ...
znajduje się inny kod. Czasami jest to poprawne, ponieważ istnieją pewne sposoby wywołania powłoki ( sh
) Bourne'a zgodnej z argumentami, aby wywołać interpreter Pythona. (Jeden z argumentów prawdopodobnie będzie zawierał python
.) Jednak dla większości celów #!/usr/bin/env python
jest prostszy, bardziej elegancki i bardziej prawdopodobne, że będzie działał tak, jak chcesz.
Wiele języków programowania i skryptów oraz niektóre inne formaty plików służą #
jako komentarz. Dla każdego z nich plik w języku może być uruchomiony przez program, który bierze go jako argument, określając program w pierwszym wierszu po #!
.
W niektórych językach programowania #
zwykle nie jest komentarzem, ale jako szczególny przypadek pierwszy wiersz jest ignorowany, jeśli zaczyna się od #!
. Ułatwia to użycie #!
składni, nawet jeśli w #
innym przypadku nie czyni komentarza wierszem.
Chociaż jest to mniej intuicyjne, każdy plik, którego format pliku może pomieścić pierwszą linię rozpoczynającą się od #!
następnej pełnej ścieżki pliku wykonywalnego, może mieć linię shebang. Jeśli to zrobisz, a plik zostanie oznaczony jako wykonywalny, możesz uruchomić go jak program ... powodując jego otwarcie jak dokument.
Niektóre aplikacje używają tego zachowania celowo. Na przykład w VMware .vmx
pliki definiują maszyny wirtualne. Możesz „uruchomić” maszynę wirtualną tak, jakby to był skrypt, ponieważ pliki te są oznaczone jako pliki wykonywalne i mają linię shebang, która powoduje ich otwarcie w narzędziu VMware.
rm
usuwa pliki. To nie jest język skryptowy. #!/bin/rm
Można jednak uruchomić plik, który zaczyna się i jest oznaczony jako wykonywalny, a po uruchomieniu rm
wywoływany jest na nim, usuwając go.
Często jest to rozumiane jako „plik sam się usuwa”. Ale plik tak naprawdę wcale nie działa. Jest to bardziej podobne do sytuacji opisanej powyżej dla .vmx
plików.
Ponieważ jednak #!
wiersz ułatwia uruchomienie prostej komendy (w tym argumentów wiersza komend), możesz w ten sposób wykonać pewne skrypty. Jako prosty przykład „skryptu” bardziej zaawansowanego niż #!/bin/rm
, rozważ:
#!/usr/bin/env tee -a
To pobiera interakcję użytkownika, odsyła go z powrotem do użytkownika wiersz po wierszu i dołącza na końcu pliku „skryptowego”.
Przydatny? Nie bardzo. Ciekawe koncepcyjnie? Całkowicie! Tak. (Nieco.)
Skrypty / programy, które są w wielu językach jednocześnie , na przykład w celu symulacji funkcji haszowania w systemach operacyjnych, które jej nie miały .
(Programy te nazywane są poliglotami , ale nie należy tego mylić z innym poczuciem poliglota w rozwoju oprogramowania , programie / projekcie, w którym różne części są napisane w różnych językach.)
Metakolecenia w QBasic / QuickBASIC, które zasygnalizowały kompilatorowi (dla skompilowanego kodu) opcje generowania kodu, ale były częścią komentarzy i dlatego zostały zignorowane podczas faktycznej kompilacji / interpretacji.
-x
flaga Pythonów ?
-x
„pomiń [s] pierwszą linię ...” druga linia jest numerowana 1
zamiast 2
, trzecia linia 2
zamiast 3
itd. Dlatego nie powinieneś używać tej flagi. ;) -x
służy do tworzenia skryptów w systemach operacyjnych innych niż Unix, których składnia podobna do shebang nie zaczyna się od #
(dlatego nie jest komentarzem w języku Python).
perl script.pl
w porównaniu ./script.pl
), a następnie interpreter będzie czytać wiersz shebang do analizowania takich jak flagi -w
. Nie zaleca się jednak polegania na tej funkcji.
Shebang to sekwencja znaków składająca się ze znaku liczby znaków i wykrzyknika (np. „#!”), Gdy występuje jako początkowe dwa znaki w początkowej linii skryptu.
W systemach operacyjnych * nix, gdy uruchamiany jest skrypt rozpoczynający się od shebang, moduł ładujący program analizuje resztę początkowej linii skryptu jako dyrektywę interpretera; zamiast tego uruchamiany jest określony program interpretera, przekazując mu jako argument ścieżkę, która była początkowo używana podczas próby uruchomienia skryptu. Na przykład, jeśli skrypt ma nazwę ścieżki „path / to / your-script” i zaczyna się od następującego wiersza:
#!/bin/sh
następnie program ładujący program jest instruowany, aby zamiast tego uruchomić program „/ bin / sh”, np. powłokę Bourne'a lub kompatybilną powłokę, przekazując „path / to / your-script” jako pierwszy argument.
W związku z tym skrypt nosi nazwę ścieżki „path / to / python-script” i zaczyna się od następującego wiersza:
#!/bin/python
następnie załadowany program jest instruowany, aby zamiast tego uruchomić program „/ bin / python”, np. interpreter języka Python, przekazując „path / to / python-script” jako pierwszy argument.
W skrócie „#” skomentuje linię, a sekwencja znaków „#!” występowanie jako pierwszych dwóch znaków w początkowej linii skryptu ma znaczenie opisane powyżej.
Aby uzyskać szczegółowe informacje, zobacz Dlaczego niektóre skrypty zaczynają się od #! ...
Źródło: Niektóre sekcje tej odpowiedzi pochodzą (z niewielkimi modyfikacjami) z Shebang (Unix) na angielskiej Wikipedii (przez autorów Wikipedii ). Ten artykuł jest objęty licencją CC-BY-SA 3.0 , tak samo jak treść użytkownika tutaj w AU, więc to wyprowadzenie jest dozwolone z przypisaniem.
#!
nazywa się, shebang
gdy występuje jako początkowe dwa znaki w początkowej linii skryptu. Jest używany w skryptach do wskazania interpretera do wykonania. shebang
Jest z systemu operacyjnego (kernel), a nie do osłony; więc nie będzie interpretowane jako komentarz.
Dzięki uprzejmości: http://en.wikipedia.org/wiki/Shebang_%28Unix%29
Ogólnie, jeśli plik jest wykonywalny, ale tak naprawdę nie jest programem wykonywalnym (binarnym), a taka linia jest obecna, program określony po #! zaczyna się od skryptu i wszystkich jego argumentów. Te dwa znaki # i! muszą być pierwszymi dwoma bajtami w pliku!
Szczegółowe informacje: http://wiki.bash-hackers.org/scripting/basics#the_shebang
Nie, jest używany tylko przez exec
wywołanie systemowe jądra Linuksa i traktowany jako komentarz przez tłumacza
Kiedy robisz na bash:
./something
w Linuksie wywołuje to wywołanie exec
systemowe ze ścieżką ./something
.
Ta linia jądra zostaje wywołana w pliku przekazanym do exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Odczytuje pierwsze bajty pliku i porównuje je #!
.
Jeśli porównanie jest prawdziwe, reszta linii jest analizowana przez jądro Linuksa, które wykonuje kolejne exec
wywołanie ze ścieżką /usr/bin/env python
i bieżącym plikiem jako pierwszym argumentem:
/usr/bin/env python /path/to/script.py
i działa to na każdy język skryptowy, który używa #
jako znaku komentarza.
I tak, możesz wykonać nieskończoną pętlę za pomocą:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash rozpoznaje błąd:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
akurat jest czytelny dla ludzi, ale nie jest to wymagane.
Jeśli plik zaczął się od różnych bajtów, exec
wywołanie systemowe użyłoby innej procedury obsługi. Innym najważniejszym wbudowanym modułem obsługi są pliki wykonywalne ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305, który sprawdza bajty 7f 45 4c 46
(które również są ludźmi) czytelne dla .ELF
). Potwierdźmy to, czytając 4 pierwsze bajty /bin/ls
, czyli plik wykonywalny ELF:
head -c 4 "$(which ls)" | hd
wynik:
00000000 7f 45 4c 46 |.ELF|
00000004
Więc kiedy jądro zobaczy te bajty, pobiera plik ELF, poprawnie zapisuje go w pamięci i rozpoczyna z nim nowy proces. Zobacz także: https://stackoverflow.com/questions/8352535/how-does-kernel-get-an-executable-binary-file-running-under-linux/31394861#31394861
Na koniec możesz dodać własne binfmt_misc
mechanizmy shebang z mechanizmem. Na przykład możesz dodać niestandardowy moduł obsługi .jar
plików . Ten mechanizm obsługuje nawet programy obsługi według rozszerzeń plików. Inną aplikacją jest przezroczyste uruchamianie plików wykonywalnych o innej architekturze za pomocą QEMU .
Nie sądzę jednak, że POSIX określa shebangs: https://unix.stackexchange.com/a/346214/32558 , chociaż wspomina o tym w sekcjach uzasadnienia oraz w formie „jeśli skrypty wykonywalne są obsługiwane przez system, coś może zdarzyć".
#include
. Tam też#
nie jest to komentarz.