Jedyną istotną różnicą jest pozyskiwanie i wykonywanie skryptu. source foo.shźródło, a wszystkie inne przykłady, które pokazujesz, są wykonywane. Bardziej szczegółowo:
./file.sh
Spowoduje to wykonanie skryptu o nazwie file.shznajdującej się w bieżącym katalogu ( ./). Zwykle po uruchomieniu commandpowłoka przeszukuje katalogi w $PATHposzukiwaniu pliku wykonywalnego o nazwie command. Jeśli podasz pełną ścieżkę, taką jak /usr/bin/commandlub ./command, wówczas $PATHjest ona ignorowana, a konkretny plik jest wykonywany.
../file.sh
Jest to w zasadzie to samo, ./file.shz wyjątkiem tego, że zamiast szukać w bieżącym katalogu file.sh, szuka w katalogu nadrzędnym ( ../).
sh file.sh
Jest to odpowiednik sh ./file.sh, jak powyżej, uruchomi skrypt wywoływany file.shw bieżącym katalogu. Różnica polega na tym, że jawnie uruchamiasz go za pomocą shpowłoki. W systemach Ubuntu tak jest dashi nie bash. Zwykle skrypty mają linię shebang, która daje program, który powinny być uruchomione jako. Wywoływanie ich za pomocą innego przesłania to. Na przykład:
$ cat foo.sh
#!/bin/bash
## The above is the shebang line, it points to bash
ps h -p $$ -o args='' | cut -f1 -d' ' ## This will print the name of the shell
Ten skrypt po prostu wypisze nazwę powłoki używanej do jej uruchomienia. Zobaczmy, co zwraca, gdy zostanie wywołany na różne sposoby:
$ bash foo.sh
bash
$ sh foo.sh
sh
$ zsh foo.sh
zsh
Wywołanie wywołania skryptu shell scriptzastąpi linię shebang (jeśli jest obecna) i uruchom skrypt z dowolną powłoką, którą mu powiesz.
source file.sh lub . file.sh
Zaskakująco nazywa się to pozyskiwaniem skryptu. Słowo kluczowe sourceto alias do wbudowanego .polecenia powłoki . Jest to sposób na wykonanie skryptu w bieżącej powłoce. Zwykle, gdy skrypt jest wykonywany, jest uruchamiany we własnej powłoce, która jest inna niż bieżąca. Ilustrować:
$ cat foo.sh
#!/bin/bash
foo="Script"
echo "Foo (script) is $foo"
Teraz, jeśli ustawię zmienną foona coś innego w powłoce nadrzędnej, a następnie uruchomię skrypt, skrypt wydrukuje inną wartość foo(ponieważ jest on również ustawiony w skrypcie), ale wartość foow powłoce nadrzędnej pozostanie niezmieniona:
$ foo="Parent"
$ bash foo.sh
Foo (script) is Script ## This is the value from the script's shell
$ echo "$foo"
Parent ## The value in the parent shell is unchanged
Jednakże, jeśli skrytuję skrypt zamiast go uruchamiać, zostanie on uruchomiony w tej samej powłoce, więc wartość fooparametru nadrzędnego zostanie zmieniona:
$ source ./foo.sh
Foo (script) is Script ## The script's foo
$ echo "$foo"
Script ## Because the script was sourced,
## the value in the parent shell has changed
Tak więc pozyskiwanie jest używane w kilku przypadkach, w których skrypt ma wpływać na powłokę, z której go uruchamiasz. Zwykle służy do definiowania zmiennych powłoki i udostępniania ich po zakończeniu skryptu.
Mając to na uwadze, powodem, dla którego otrzymujesz różne odpowiedzi, jest przede wszystkim to, że twój skrypt nie robi tego, co myślisz. Zlicza ile razy bashpojawia się na wyjściu ps. To nie jest liczba otwartych terminali , to liczba uruchomionych powłok (w rzeczywistości tak nie jest, ale to kolejna dyskusja). Aby to wyjaśnić, uprościłem nieco twój skrypt:
#!/bin/bash
logname=terdon
not=`ps -au$logname | grep -c bash`
echo "The number of shells opened by $logname is $not"
I uruchom go na różne sposoby z otwartym tylko jednym terminalem:
Bezpośrednie uruchomienie, ./foo.sh.
$ ./foo.sh
The number of shells opened by terdon is 1
Tutaj używasz linii shebang. Oznacza to, że skrypt jest wykonywany bezpośrednio przez cokolwiek tam ustawione. Wpływa to na sposób wyświetlania skryptu na wyjściu ps. Zamiast być wymienionym jako bash foo.sh, zostanie pokazany tylko jako, foo.shco oznacza, że grepgo przegapisz. W rzeczywistości działają 3 instancje bash: proces nadrzędny, bash uruchamiający skrypt i kolejna, która uruchamia pspolecenie . To ostatnie jest ważne, uruchomienie polecenia z podstawieniem polecenia ( `command`lub $(command)) powoduje uruchomienie kopii powłoki nadrzędnej i uruchomienie polecenia. Tutaj jednak żadne z nich nie jest pokazane ze względu na sposób, w jaki pspokazuje on swoje wyniki.
Uruchamianie bezpośrednie za pomocą jawnej powłoki (bash)
$ bash foo.sh
The number of shells opened by terdon is 3
Tutaj, ponieważ biegasz z bash foo.sh, wynik pswyświetli się bash foo.shi zostanie policzony. Mamy tutaj proces nadrzędny, bashuruchomienie skryptu i sklonowaną powłokę (uruchomienie ps), ponieważ teraz pspokaże każdy z nich, ponieważ twoje polecenie będzie zawierać słowo bash.
Uruchamianie bezpośrednie za pomocą innej powłoki ( sh)
$ sh foo.sh
The number of shells opened by terdon is 1
Jest inaczej, ponieważ uruchamiasz skrypt za pomocą shi nie bash. Dlatego jedyną bashinstancją jest powłoka nadrzędna, w której uruchomiono skrypt. shZamiast tego uruchamiane są wszystkie pozostałe wyżej wymienione powłoki .
Pozyskiwanie (przez .lub to sourcesamo)
$ . ./foo.sh
The number of shells opened by terdon is 2
Jak wyjaśniono powyżej, pozyskiwanie skryptu powoduje, że działa on w tej samej powłoce co proces nadrzędny. Jednak oddzielna podpowłoka jest uruchamiana w celu uruchomienia pspolecenia, co daje całkowitą liczbę dwóch.
Na koniec poprawnym sposobem zliczania uruchomionych procesów nie jest parsowanie, psale użycie pgrep. Wszystkich tych problemów można by uniknąć, gdybyś po prostu biegł
pgrep -cu terdon bash
Tak więc działającą wersją skryptu, która zawsze drukuje prawidłową liczbę, jest (zauważ brak zastępowania poleceń):
#!/usr/bin/env bash
user="terdon"
printf "Open shells:"
pgrep -cu "$user" bash
To zwróci 1 po źródle i 2 (ponieważ zostanie uruchomiony nowy bash, aby uruchomić skrypt) dla wszystkich innych sposobów uruchamiania. Nadal zwróci 1 po uruchomieniu, shponieważ proces potomny nie jest bash.