Jaka jest różnica między wykonywaniem skryptu Bash a jego pozyskiwaniem?

Odpowiedzi:

337

Krótka odpowiedź

Pozyskanie skryptu spowoduje uruchomienie poleceń 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 wykonać inaczej.

Jeśli nadal jesteś zdezorientowany, czytaj dalej.

Terminologia

Aby wyjaśnić niektóre typowe nieporozumienia dotyczące składni do wykonania i składni do źródła:

./myscript

Będzie to execute 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żącego katalogu zwykle nie ma (i zwykle nie powinno być) $PATH.

myscript

Będzie to wykonać myscript , jeśli plik jest wykonywalny i znajduje się w jakimś katalogu w $PATH.

source myscript

To będzie źródło myscript . Plik nie musi być wykonywalny, ale musi być prawidłowym skryptem powłoki. Plik może znajdować się w bieżącym katalogu lub w katalogu w $PATH.

. myscript

To również źródło myscript . Ta „pisownia” jest oficjalna zgodnie z definicją POSIX . Bash zdefiniowany sourcejako alias do kropki.

Demonstracja

Rozważ myscript.shnastępujące treś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

Przed wykonaniem skryptu najpierw sprawdzamy bieżące środowisko:

$ env | grep FOO
$ echo $PWD
/home/lesmana

Zmienna FOOnie jest zdefiniowana i jesteśmy w katalogu domowym.

Teraz wykonujemy plik:

$ ./myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Sprawdź ponownie środowisko:

$ env | grep FOO
$ echo $PWD
/home/lesmana

Zmienna FOOnie jest ustawiona, a katalog roboczy nie zmienił się.

Dane wyjściowe skryptu wyraźnie pokazują, że zmienna została ustawiona, a katalog został zmieniony. Następnie kontrola pokazuje, że zmienna nie jest ustawiona, a katalog się nie zmienia. Co się stało? Zmiany zostały wprowadzone w nowej powłoce. Prąd powłoki zrodził nową powłokę, aby uruchomić skrypt. Skrypt działa w nowej powłoce, a wszystkie zmiany w środowisku obowiązują w nowej powłoce. Po zakończeniu skryptu nowa powłoka jest niszczona. Wszystkie zmiany środowiska w nowej powłoce są niszczone przez nową powłokę. Tylko tekst wyjściowy jest drukowany w bieżącej powłoce.

Teraz źródło pliku:

$ source myscript.sh
foo:
foo: FOO=foo
PWD: /home/lesmana
PWD: /home/lesmana/somedir

Sprawdź ponownie środowisko:

$ env | grep FOO
FOO=foo
$ echo $PWD
/home/lesmana/somedir

Zmienna FOO została ustawiona, a katalog roboczy zmienił się.

Pozyskanie skryptu nie tworzy nowej powłoki. Wszystkie polecenia są uruchamiane w bieżącej powłoce, a zmiany w środowisku obowiązują w bieżącej powłoce.

Zauważ, że w tym prostym przykładzie wynik wykonania jest taki sam, jak pozyskiwanie skryptu. Nie zawsze tak jest.

Kolejna demonstracja

Rozważ następujący skrypt pid.sh:

#!/bin/sh
echo $$

(specjalna zmienna $$rozwija się do PID aktualnie działającego procesu powłoki)

Najpierw wydrukuj PID bieżącej powłoki:

$ echo $$
25009

Źródło skryptu:

$ source pid.sh
25009

Uruchom skrypt, zwróć uwagę na PID:

$ ./pid.sh
25011

Źródło ponownie:

$ source pid.sh
25009

Wykonaj ponownie:

$ ./pid.sh
25013

Widać, że pozyskiwanie skryptu odbywa się w tym samym procesie, a wykonanie skryptu powoduje utworzenie nowego procesu za każdym razem. Ten nowy proces to nowa powłoka, która została stworzona do wykonania skryptu. Pozyskanie skryptu nie tworzy nowej powłoki, a zatem PID pozostaje taki sam.

streszczenie

Zarówno wyszukiwanie, jak i wykonywanie skryptu spowoduje uruchamianie poleceń w skrypcie wiersz po wierszu, tak jakbyś wpisywał te polecenia ręcznie wiersz po wierszu.

Różnice są następujące:

  • Po uruchomieniu skryptu otwierasz nową powłokę, wpisz polecenia w nowej powłoce, skopiuj dane wyjściowe z powrotem do bieżącej powłoki, a następnie zamknij nową powłokę. Wszelkie zmiany w środowisku będą obowiązywać tylko w nowej powłoce i zostaną utracone po zamknięciu nowej powłoki.
  • Podczas generowania skryptu wpisujesz polecenia w bieżącej powłoce. Wszelkie zmiany środowiska zostaną zastosowane i pozostaną w bieżącej powłoce.

Użyj źródła, jeśli chcesz, aby skrypt zmienił środowisko w aktualnie uruchomionej powłoce. użyj wykonać inaczej.


Zobacz też:

lesmana
źródło
2
Jednym z zastosowań pozyskiwania jest stworzenie podstawowej formy pliku konfiguracyjnego dla twoich skryptów. Zaczynasz od ustawienia różnych zmiennych na wartości domyślne, a następnie na źródło w coś takiego jak myscript.conf - a ten skrypt źródłowy może mieć instrukcje przypisania, które zastępują dowolne wartości. Ponieważ pobrany skrypt nie zaczyna się od # / bin / bash, nie jest zalecane, aby wykonać go bezpośrednio.
LawrenceC
Więc source jest jak uruchamianie go w zasięgu globalnym, a wykonanie powoduje utworzenie nowego zasięgu lokalnego. Czy można to rozszerzyć na funkcję w skrypcie? wykonać funkcję (normalnie) czy „ją„ zinterpretować ”?
aliteralmind,
2
Czy istnieje różnica między używaniem source myscript.sha . myscript.sh?
Holloway,
2
praktycznie nie ma różnicy, jeśli używasz bash. source to alias do kropki w bash.
lesmana
1
Uwielbiam to, gdy ludzie podają tak wyszukane przykłady, aby nawet początkujący użytkownicy Linuksa tacy jak ja mogli zrozumieć. Dzięki!
Julius
21

Wykonanie skryptu powoduje uruchomienie go w osobnym procesie potomnym, tzn. W celu przetworzenia skryptu wywoływana jest osobna instancja powłoki. Oznacza to, że żadnych zmiennych środowiskowych itp. Zdefiniowanych w skrypcie nie można aktualizować w powłoce nadrzędnej (bieżącej).

Pozyskanie skryptu oznacza, że ​​jest on analizowany i wykonywany przez samą bieżącą powłokę. To tak, jakbyś wpisał treść skryptu. Z tego powodu skrypt nie musi być wykonywalny. Ale oczywiście musi być wykonywalny.

Jeśli masz argumenty pozycyjne w bieżącej powłoce, są one niezmienione.

Więc jeśli mam plik a.shzawierający:

echo a $*

i robię:

$ set `date`
$ source ./a.sh

Dostaję coś takiego:

a Fri Dec 11 07:34:17 PST 2009

Natomiast:

$ set `date`
$ ./a.sh

daje mi:

a

Mam nadzieję, że to pomaga.

Alok
źródło
5
chociaż ta odpowiedź jest poprawna pod każdym względem, bardzo trudno ją zrozumieć, ponieważ została wykazana przy użyciu innej koncepcji (ustawiania parametrów pozycyjnych), co moim zdaniem jest jeszcze bardziej mylące niż różnica w pozyskiwaniu i wykonywaniu samej siebie.
lesmana
9

pozyskiwanie jest zasadniczo takie samo, jak wpisywanie każdej linii skryptu w wierszu polecenia pojedynczo ...

Wykonanie rozpoczyna nowy proces, a następnie uruchamia każdą linię skryptu, modyfikując tylko bieżące środowisko o to, co zwraca.

John Weldon
źródło
6

Oprócz powyższego wykonanie skryptu ./myscriptwymaga uprawnień do wykonywania skryptu myscript, podczas gdy pozyskiwanie nie wymaga uprawnień do wykonywania. Dlatego wcześniej chmod +x myscriptnie jest to wymaganesource myscript

abs
źródło
2
To prawda, ale jeśli to jest problem, zawsze możesz uruchomić bash myscript.
Daniel Beck
5

Pozyskiwanie zawiera wszystkie dodatkowe zmienne zdefiniowane w skrypcie.
Więc jeśli masz konfiguracje lub definicje funkcji, powinieneś je pobrać, a nie wykonać. Wykonania są niezależne od środowiska rodziców.

Arkaitz Jimenez
źródło
3

Jeśli dobrze pamiętam, wykonanie skryptu uruchamia plik wykonywalny w #!wierszu z plikiem skryptu jako argumentem (zazwyczaj uruchamianie nowej powłoki i efektywne pozyskiwanie skryptu do nowej powłoki, jak w przypadku #!/bin/sh);
podczas gdy pozyskiwanie skryptu powoduje wykonanie każdego wiersza w bieżącym środowisku powłoki, co jest przydatne do mutowania bieżącej powłoki (na przykład umożliwiając zdefiniowanie funkcji powłoki i eksport zmiennych środowiskowych).

Shekhar
źródło
2

sourcepolecenie wykonuje podany skrypt (uprawnienie do wykonywania nie jest obowiązkowe ) w bieżącym środowisku powłoki, natomiast ./wykonuje podany skrypt wykonywalny w nowej powłoce.

Sprawdź również tę odpowiedź, na przykład: https://superuser.com/a/894748/432100

Ostra Wacharia
źródło