Jaka jest różnica między pozyskiwaniem („.” Lub „source”) a uruchamianiem pliku w bash?

76

Jaka jest różnica między wykonywaniem takiego skryptu:

./test.sh

i wykonanie takiego skryptu:

. test.sh?

Próbowałem prostego, dwuwierszowego skryptu, aby sprawdzić, czy mogę znaleźć różnicę:

#!/bin/bash
ls

Ale oba . test.shi ./test.shzwróciły te same informacje.

Natan
źródło
Przepraszam, jeśli jest to duplikat - po dalszym dochodzeniu znalazłem kilka stron z istotnymi informacjami, szukając „kropki bash” zamiast „bash”.
Natan
3
Podobnie jak test.shnie jest to samo co ./test.sh(pierwsze wywołuje PATHwyszukiwanie), tak . test.shi są . ./test.shróżne w ten sam sposób (pierwsze wywołuje PATHwyszukiwanie). Wiele powłok wydaje się domyślnie zawierać .na końcu PATHpodczas .wyszukiwania ścieżki, ale takie zachowanie nie jest standardowe. Tak więc, jest bardziej dokładne, aby porównać test.shvs . test.shi ./test.shkontra . ./test.sh.
jw013

Odpowiedzi:

83

./test.shdziała test.shjako osobny program. Może się zdarzyć, że jest to skrypt bash, jeśli plik test.shzaczyna się od #!/bin/bash. Ale może to być coś zupełnie innego.

. ./test.shwykonuje kod pliku test.shwewnątrz działającej instancji bash. Działa tak, jakby plik zawartości test.shzostał dołączony tekstowo zamiast . ./test.shwiersza. (Prawie: istnieje kilka szczegółów, które się różnią, takich jak wartość $BASH_LINENOi zachowanie returnwbudowanego.)

source ./test.shjest identyczny jak . ./test.shw bash (w innych powłokach sourcemoże być nieco inny lub może zupełnie nie istnieć; .do włączenia jest w standardzie POSIX).

Najbardziej widoczną różnicą między uruchomieniem osobnego skryptu z wbudowanym skryptem ./test.shi włączeniem go .jest to, że jeśli test.shskrypt ustawia niektóre zmienne środowiskowe, w osobnym procesie, ustawiane jest tylko środowisko procesu potomnego, zaś w przypadku włączenia skryptu środowisko jedynego procesu powłoki jest ustawiony. Jeśli dodać linię foo=barw test.sh, a echo $foona koniec skryptu wywołującego, zobaczysz różnicę:

$ cat test.sh
#!/bin/sh
foo=bar
$ ./test.sh
$ echo $foo

$ . ./test.sh
$ echo $foo
bar
Gilles
źródło
17
Również dodanie echo $$do skryptu pokaże różnicę całkiem wyraźnie. $$Zmienna posiada PID bieżącej powłoki.
1
Innym scenariuszem użycia jest użycie . ./test.shwywołania z innego skryptu powłoki, aby użyć funkcji opisanych w test.sh. Mam na myśli, że nie tylko zmienne można ustawić, możesz także tworzyć nowe funkcje w ten sposób, które można wywołać z bash lub z innego skryptu. . /usr/libexec/company/tools; custom_command "variable
Rqomey,
9

Uruchomienie skryptu w pierwszy sposób uruchamia go jako proces potomny. Z drugiej strony Sourcing (drugi sposób) uruchamia skrypt tak, jakbyś wprowadził wszystkie jego polecenia do bieżącej powłoki - jeśli skrypt ustawi zmienną, pozostanie ustawiony, jeśli skrypt zakończy działanie, sesja zakończy się. Zobacz help .dokumentację.

choroba
źródło
3

Inną rzeczą, na którą zwracam uwagę jest to, że jeśli masz taki alias:

# add into .bashrc_aliases
alias ls='ls -lht'

Z ./test.shdostaniesz normalne lswyjście (i inną niż bieżąca PID shell):

auraham@pandora:~/iso$ ./test.sh 
dsl-4.4.10.iso  test.sh
3136 # PID

Z . test.shlub . ./test.shotrzymasz bardziej szczegółowy wynik (i ten sam PID niż bieżąca powłoka):

auraham@pandora:~/iso$ echo $$
2767 # shell PID

auraham@pandora:~/iso$ . test.sh 
total 50M
drwxrwxr-x  2 auraham auraham 4.0K Jul 30 15:41 .
-rwxrwxr-x  1 auraham auraham   32 Jul 30 15:41 test.sh
drwxr-xr-x 50 auraham auraham 4.0K Jul 30 15:30 ..
-rw-rw-r--  1 auraham auraham  50M Jul 28 17:24 dsl-4.4.10.iso
2767 # PID
auraham
źródło
Możesz to uwzględnić w .bashrc if [ -f ~/.bash_aliases ]; then . ~/.bash_aliases fi Następnie, wstaw swoje aliasy .bash_aliases.
auraham
Oczywiście, ale czy nadal nie musisz używać aliassłowa kluczowego? (Może to tylko pomyłka w twoim poście - na linii 3?)
Emanuel Berg
całkowicie poprawne, mój błąd. Dzięki @EmanuelBerg
auraham
-1

Głównym zastosowaniem dla mnie source(lub .) są funkcje bash .

Mam skrypty z wieloma funkcjami i wykonuję je wszystkie za pomocą moich .bashrc. Funkcje „stają się” poleceniami, których często używam.

Willian Paixao
źródło
Próbowałem wszystkich trzech metod w .bashrc - source, bezwzględna pozycja skryptu i nazwa polecenia (umieszczenie skryptu w folderze PATH) - i wszystkie trzy metody działały.
Emanuel Berg