Jaka jest różnica między wykonywaniem skryptu Bash a jego pozyskiwaniem?
Jaka jest różnica między wykonaniem skryptu Bash takiego jak A a pozyskiwaniem skryptu Bash takiego jak B?
A
> ./myscript
B
> source myscript
Odbiorca skryptu uruchomi polecenia w bieżącym procesie powłoki.
Wykonanie skryptu spowoduje uruchomienie poleceń w nowym procesie powłoki.
Użyj źródła, jeśli chcesz, aby skrypt zmienił środowisko w aktualnie uruchomionej powłoce. użyj wykonaj w przeciwnym wypadku.
Jeśli nadal jesteś zdezorientowany, czytaj dalej.
Aby wyjaśnić pewne powszechne nieporozumienia dotyczące składni execute i składni source:
./myscript
To wykona myscript
pod warunkiem, że plik jest wykonywalny i znajduje się w bieżącym katalogu. Wiodąca kropka i ukośnik (./
) oznaczają bieżący katalog. Jest to konieczne, ponieważ bieżący katalog zwykle nie jest (i zwykle nie powinien być) w $PATH
.
myscript
To spowoduje wykonanie myscript
, jeśli plik jest wykonywalny i znajduje się w jakimś katalogu w $PATH
.
source myscript
Spowoduje to zasilenie myscript
. Plik nie musi być wykonywalny, ale musi być poprawnym skryptem powłoki. Plik może znajdować się w bieżącym katalogu lub w katalogu w $PATH
.
. myscript
To również będzie źródło myscript
. Ta “pisownia” jest oficjalną pisownią zdefiniowaną przez POSIX . Bash zdefiniował source
jako alias do kropki.
Rozważmy myscript.sh
z następującą zawartością:
#!/bin/sh
# demonstrate setting a variable
echo "foo: "$(env | grep FOO)
export FOO=foo
echo "foo: "$(env | grep FOO)
# demonstrate changing of working directory
echo "PWD: "$PWD
cd somedir
echo "PWD: "$PWD
Zanim wykonamy skrypt, najpierw sprawdzamy aktualne środowisko:
$ env | grep FOO
$ echo $PWD
/home/lesmana
Zmienna FOO
nie jest zdefiniowana i znajdujemy się w katalogu domowym.
Teraz wykonujemy wykonanie pliku:
$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
Sprawdzamy ponownie środowisko:
$ env | grep FOO
$ echo $PWD
/home/lesmana
Zmienna FOO
nie jest ustawiona, a katalog roboczy nie uległ zmianie.
Wyjście skryptu wyraźnie pokazuje, że zmienna została ustawiona i katalog został zmieniony. Późniejsze sprawdzenie pokazuje, że zmienna nie jest ustawiona, a katalog nie został zmieniony. Co się stało? Zmiany zostały dokonane w nowej powłoce. Powłoka current wywołała nową powłokę, aby uruchomić skrypt. Skrypt jest uruchamiany w nowej powłoce i wszystkie zmiany w środowisku zaczynają obowiązywać w nowej powłoce. Po wykonaniu skryptu nowa powłoka jest niszczona. Wszystkie zmiany w środowisku w nowej powłoce są niszczone wraz z nową powłoką. Jedynie tekst wyjściowy jest wypisywany w bieżącej powłoce.
Teraz pochodzimy z pliku:
$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir
Sprawdzamy ponownie środowisko:
$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir
Zmienna FOO jest ustawiona, a katalog roboczy uległ zmianie.
Wykonanie skryptu nie powoduje utworzenia nowej powłoki. Wszystkie polecenia są wykonywane w bieżącej powłoce, a zmiany w środowisku zaczynają obowiązywać w bieżącej powłoce.
Zauważ, że w tym prostym przykładzie wynik wykonania jest taki sam, jak źródło skryptu. Niekoniecznie zawsze tak jest.
Rozważmy następujący skrypt pid.sh
:
#!/bin/sh
echo $$
(zmienna specjalna $$
interpretowana jest jako PID aktualnie uruchomionego procesu powłoki)
Najpierw wypisz PID bieżącej powłoki:
$ echo $$
25009
Źródło skryptu:
$ source pid.sh
25009
Wykonaj skrypt, zwróć uwagę na PID:
$ ./pid.sh
25011
Źródło ponownie:
$ source pid.sh
25009
Wykonaj ponownie:
$ ./pid.sh
25013
Możesz zobaczyć, że źródło skryptu działa w tym samym procesie, podczas gdy wykonywanie skryptu tworzy nowy proces za każdym razem. Tym nowym procesem jest nowa powłoka, która została utworzona do wykonania skryptu. Sourcing skryptu nie tworzy nowej powłoki i dlatego PID pozostaje taki sam.
Zarówno pozyskiwanie jak i wykonywanie skryptu uruchomi polecenia w skrypcie linia po linii, tak jakbyś wpisał te polecenia ręcznie linia po linii.
Różnice są następujące:
Użyj source jeśli chcesz by skrypt zmienił środowisko w twojej aktualnie uruchomionej powłoce. użyj execute w przeciwnym wypadku.
Zobacz także:
Wykonywanie skryptu uruchamia go w oddzielnym procesie potomnym, tj. do przetwarzania skryptu wywoływana jest oddzielna instancja powłoki. Oznacza to, że wszelkie zmienne środowiskowe itp. zdefiniowane w skrypcie nie mogą być aktualizowane w powłoce rodzica (bieżącej).
Sourcing skryptu oznacza, że jest on parsowany i wykonywany przez samą bieżącą powłokę. To tak, jakbyś wpisał zawartość skryptu. Z tego powodu, pozyskiwany skrypt nie musi być wykonywalny. Ale musi być wykonywalny, jeśli go wykonujesz, oczywiście.
Jeśli masz argumenty pozycyjne w bieżącej powłoce, to są one niezmienione.
Więc jeśli mam plik a.sh
zawierający:
echo a $*
i robię:
$ set `date`
$ source ./a.sh
otrzymam coś takiego jak:
a Fri Dec 11 07:34:17 PST 2009
Natomiast:
$ set `date`
$ ./a.sh
daje mi:
a
Mam nadzieję, że to pomoże.
Sourcing jest zasadniczo tym samym, co wpisywanie każdej linii skryptu w wierszu poleceń po kolei…
Wykonanie uruchamia nowy proces, a następnie uruchamia każdą linię skryptu, modyfikując tylko bieżące środowisko tym, co zwraca.
Sourcing dostaniesz wszystkie dodatkowe zmienne zdefiniowane w skrypcie.
Więc jeśli masz configi lub definicje funkcji, powinieneś je pozyskać, a nie wykonywać. Wykonania są niezależne od środowiska rodzica.
Polecenie source
wykonuje podany skrypt (zezwolenie na wykonanie jest nieobowiązkowe )w bieżącym środowisku powłoki, natomiast ./
wykonuje podany wykonalny skrypt w nowej powłoce.
Sprawdź również tę odpowiedź dla przykładu: https://superuser.com/a/894748/432100