Mam projekt składający się z około 20 małych .sh
plików. Nazywam je „małymi”, ponieważ ogólnie żaden plik nie ma więcej niż 20 linii kodu. Przyjąłem podejście modułowe, ponieważ dlatego jestem wierny filozofii Uniksa i łatwiej jest mi utrzymać projekt.
Na początku każdego .sh
pliku umieszczam #!/bin/bash
.
Mówiąc prosto, rozumiem, że deklaracje skryptów mają dwa cele:
- Pomagają użytkownikowi przypomnieć sobie, jaka powłoka jest potrzebna do uruchomienia pliku (powiedzmy, po kilku latach bez używania pliku).
- Zapewniają, że skrypt działa tylko z określoną powłoką (w tym przypadku Bash), aby zapobiec nieoczekiwanemu zachowaniu w przypadku użycia innej powłoki.
Kiedy projekt zaczyna rosnąć z powiedzmy 5 plików do 20 plików lub z 20 plików do 50 plików (nie w tym przypadku, ale tylko w celu wykazania), mamy 20 linii lub 50 linii deklaracji skryptu. Przyznaję, choć niektórym może to być zabawne, wydaje mi się, że używanie 20 lub 50 jest trochę zbędne, zamiast tego mówię tylko o 1 na projekt (może w głównym pliku projektu).
Czy istnieje sposób na uniknięcie rzekomej redundancji 20 lub 50 lub znacznie większej liczby wierszy deklaracji skryptu poprzez użycie jakiejś „globalnej” deklaracji skryptu w jakimś głównym pliku?
źródło
/bin/bash -x "$script"
Odpowiedzi:
Nawet jeśli twój projekt może teraz składać się wyłącznie z 50 skryptów Bash, prędzej czy później zacznie gromadzić skrypty napisane w innych językach, takich jak Perl lub Python (dla korzyści, jakie te języki skryptowe mają, których Bash nie ma).
Bez odpowiedniej linii
#!
w każdym skrypcie bardzo trudno byłoby używać różnych skryptów, nie wiedząc również, jakiego interpretera użyć. Nie ma znaczenia, czy każdy skrypt jest wykonywany z innych skryptów , to tylko przenosi trudność od użytkowników końcowych do programistów. Żadna z tych dwóch grup osób nie powinna wiedzieć, w jakim języku został napisany skrypt, aby móc go używać.Skrypty powłoki wykonywane bez linii-line
#!
i bez wyraźnego interpretera są wykonywane na różne sposoby w zależności od tego, która powłoka je wywołuje (patrz np. Pytanie Który interpreter powłoki uruchamia skrypt bez shebang? A zwłaszcza odpowiedź Stéphane'a ), co nie jest tym, czego chcesz w środowisku produkcyjnym (potrzebujesz spójnego zachowania, a być może nawet przenośności).Skrypty wykonane za pomocą jawnego interpretera będą uruchamiane przez tego tłumacza niezależnie od tego, co
#!
mówi linia. Spowoduje to problemy w dalszej kolejności, jeśli zdecydujesz się na ponowne wdrożenie, powiedzmy, skryptu Bash w Pythonie lub innym języku.Powinieneś wydać te dodatkowe naciśnięcia klawiszy i zawsze dodawać
#!
-linię do każdego skryptu.W niektórych środowiskach w każdym skrypcie każdego projektu znajdują się legalne teksty zawierające wiele akapitów. Bardzo się ciesz, że to tylko
#!
linia, która wydaje się „zbędna” w twoim projekcie.źródło
#!
linii, gdy tylko plik ma uzasadnione uprawnienia i nie jest ładowany przez interpretera, ale przez powłokę. Oznacza to, że/path/to/myprog.pl
uruchamia program perla, jeśli#!
linia jest obecna (wskazując na interpreter perla), a plik ma uprawnienia do wykonania.Nie rozumiesz sensu
#!
. Uruchamianie tego programu w ramach zdefiniowanego interpretera jest w istocie dyrektywą dla systemu operacyjnego.Tak więc skrypt może być,
#!/usr/bin/perl
a wynikowy program może być uruchomiony jako./myprogram
i można użyć interpretera perla. Podobnie#!/usr/bin/python
spowodowałoby, że program działałby w Pythonie.Więc linia
#!/bin/bash
mówi systemowi operacyjnemu, aby uruchomił ten program w bash.Oto przykład:
Tak więc, mimo że moją powłoką jest ksh, program „x” działa pod kontrolą bash z powodu
#!
linii i możemy to wyraźnie zobaczyć na liście procesów.źródło
ps -aux
może dać ostrzeżenie,ps
dają ostrzeżenieWarning: bad syntax, perhaps a bogus '-'?
.ps
suooprts zarówno składnia argumentów BSD, jak i UXIX .-aux
jest źle UNIX Stephen prawdopodobnie oznacza, żeaux
jest poprawny BSDps
pokazuje wywołaniebash
), a nie na jawnej składni; (2)ps -aux
działa doskonale na CentOS 7 i Debian 9 bez ostrzeżeń; ta cut'n'paste była dokładnie wyjściem z mojej maszyny; cała dyskusja na temat tego, czy-
jest potrzebna czy nie, dotyczy starszych wersji systemu Linux, a nie bieżących wersji.Na
.sh
Złe jest
.sh
na końcu nazwy pliku.Wyobraź sobie, że przepisujesz jeden ze skryptów w Pythonie.
Cóż, teraz musisz zmienić pierwszy wiersz na
#!/usr/bin/python3
taki, który nie jest taki zły, ponieważ musiałeś zmienić również co drugi wiersz kodu w pliku. Jednak musisz także zmienić nazwę pliku zprog.sh
naprog.py
. Następnie musisz znaleźć wszędzie w innych skryptach i wszystkich skryptach użytkownika (te, o których istnieniu nawet nie wiedziałeś, że istnieją), i zmienić je, aby używały nowego skryptu.sed -e 's/.sh/.py/g'
może pomóc tym, o których wiesz. Ale teraz Twoje narzędzie kontroli wersji pokazuje zmianę w wielu niepowiązanych plikach.Alternatywnie zrobić to tak, Unix i nazwa programu
prog
nieprog.sh
.Na
#!
Jeśli masz prawidłową
#!
wartość i ustaw uprawnienie / tryb na wykonanie. Więc nie musisz znać tłumacza. Komputer zrobi to za Ciebie.W przypadku systemów innych niż GNU przeczytaj instrukcję
chmod
(i naucz się ósemki), być może i tak ją przeczytasz.źródło
.image
na zdjęcia..audio
dla dźwięku itp. Mówiąc ci, co to jest, ale nie o implementacji / kodowaniu.launch-missiles
lubdelete-project-and-make-manager-pissed
nie chcę „po prostu go uruchomić”, gdy byłem tylko ciekawy języka :)file
polecenia. rozpoznaje większość typów plików.Prawdopodobnie warto zauważyć, że jest to całkowicie błędne. Linia hashbanga w żaden sposób nie uniemożliwia próby podania pliku do niepoprawnej powłoki / interpretera:
(lub podobnie z
awk -f array.sh
itp.)Ale w każdym razie innym podejściem do modułowości byłoby zdefiniowanie funkcji powłoki w plikach, jednej funkcji na plik, jeśli chcesz, a następnie
source
plików z programu głównego. W ten sposób nie potrzebujesz hashbangów: będą one traktowane jak inne komentarze i wszystko będzie działało przy użyciu tej samej powłoki. Minusem byłoby to, że potrzebujeszsource
plików z funkcjami (np.for x in functions/*.src ; do source "$x" ; done
), A wszystkie one działałyby przy użyciu tej samej powłoki, więc nie można bezpośrednio zastąpić jednego z nich implementacją Perla.źródło
Istnieje - nazywa się to przenośnością lub zgodnością z POSIX. Staraj się zawsze pisać skrypty w przenośny, neutralny dla powłoki sposób, źródłuj je tylko ze skryptu, który używa
#!/bin/sh
lub gdy używasz/bin/sh
interaktywnie (lub przynajmniej powłoki zgodnej z POSIX, takiej jakksh
).Jednak przenośne skrypty nie ratują Cię przed:
/bin/sh
skryptcsh
.Jeśli mogę wyrazić swoją opinię, „unikanie redundancji” poprzez wyeliminowanie
#!
jest złym celem. Celem powinna być spójna wydajność, a właściwie działający skrypt, który działa i uwzględnia przypadki narożników, przestrzega pewnych ogólnych zasad, takich jak nieparsowanie-ls lub zawsze cytowanie zmiennych-chyba, że trzeba rozdzielać słowa .Naprawdę nie są przeznaczone dla użytkownika - służą systemowi operacyjnemu do prawidłowego działania interpretera. „Właściwy” w tym przypadku oznacza, że OS znajduje to, co jest w shebang; jeśli kod pod nim dla złej powłoki - to wina autora. Jeśli chodzi o pamięć użytkownika, nie sądzę, aby „użytkownik” programów takich jak Microsoft Word lub Google Chrome kiedykolwiek potrzebował wiedzieć, w jakim języku są napisane programy; autorzy mogą potrzebować.
Z drugiej strony skrypty napisane przenośnie mogą wyeliminować konieczność pamiętania, która powłoka była pierwotnie używana, ponieważ skrypty przenośne powinny działać w dowolnej powłoce zgodnej z POSIX.
Oni nie. Tym, co faktycznie zapobiega nieoczekiwanemu zachowaniu, jest pisanie przenośnych skryptów.
źródło
Powodem, dla którego musisz umieścić
#!/bin/bash
na górze każdego skryptu, jest to, że uruchamiasz go jako osobny proces.Po uruchomieniu skryptu jako nowego procesu, system operacyjny widzi, że jest to plik tekstowy (w przeciwieństwie do binarnego pliku wykonywalnego) i musi wiedzieć, który interpreter ma wykonać. Jeśli tego nie powiesz, system operacyjny może tylko zgadywać, używając domyślnego ustawienia (które administrator może zmienić). Tak więc
#!
linia (plus oczywiście dodawanie uprawnień do plików wykonywalnych) zamienia prosty plik tekstowy w plik wykonywalny, który można uruchomić bezpośrednio, mając pewność, że system operacyjny wie, co z tym zrobić.Jeśli chcesz usunąć
#!
linię, masz następujące opcje:Wykonaj skrypt bezpośrednio (tak jak teraz) i mam nadzieję, że domyślny interpreter pasuje do skryptu - prawdopodobnie jesteś bezpieczny na większości systemów Linux, ale nie można go przenosić na inne systemy (np. Solaris) i można go zmienić na cokolwiek (mógłbym nawet ustawić, aby działało
vim
na pliku!).Wykonaj skrypt za pomocą
bash myscript.sh
. Działa to dobrze, ale musisz podać ścieżkę do skryptu, i jest to bałagan.Skrypt źródłowy należy użyć
. myscript.sh
, który uruchamia skrypt w ramach bieżącego procesu tłumacza (tj. Nie jako podproces). Ale prawie na pewno będzie to wymagać modyfikacji twoich skryptów i sprawi, że będą mniej modułowe / wielokrotnego użytku.W przypadkach 2 i 3 plik nie potrzebuje (i nie powinien mieć) uprawnień do wykonywania, a nadanie mu
.sh
(lub.bash
) sufiksu jest dobrym pomysłem.Ale żadna z tych opcji nie wygląda dobrze dla twojego projektu, ponieważ powiedziałeś, że chcesz zachować swoje skrypty modułowe (=> niezależne i niezależne), więc powinieneś trzymać
#!/bin/bash
linię na górze skryptów.W swoim pytaniu powiedziałeś również, że postępujesz zgodnie z filozofią uniksową. Jeśli to prawda, powinieneś dowiedzieć się, do czego
#!
tak naprawdę jest linia, i używać jej w każdym skrypcie wykonywalnym!źródło
then you should learn what the #! line is really for, and keep using it in every executable script!
. Filozofię U. można podążać w górę do pewnego punktu wiedzy. Po tych wszystkich odpowiedziach zrozumiałem, dlaczego można je włączyć do tego terminu. Proponuję zredagować odpowiedź, zastępując ją: „Zobacz shebang jako wewnętrzną część filozofii uniksowej, którą szanujesz i adoptujesz”.