Jaka jest różnica między „źródłem x”, „. x ”i„ ./x ”w Bash?

11

Mam jedno źródło bash run.shw następujący sposób,

#!/bin/bash
if [ $# -ne 1 ]; then
    exit
fi
...

kiedy wykonuję to na dwa sposoby, są różne zachowania. Pierwszy sposób to

source run.sh

Zamknie terminal po wykonaniu. Drugi sposób to

./run.sh

to po prostu zakończy działanie skryptu i pozostanie na terminalu. Pytam, czy istnieje polecenie wyjścia ze skryptów bash dla obu source run.shi ./run.shwykonania. Próbowałem returnteż, co nie działa dobrze w trakcie ./run.shwykonywania.

Mówiąc bardziej ogólnie, interesuje mnie, dlaczego tak się dzieje i jaka jest różnica między użyciem „źródła” i „.” do wykonania skryptu?

Richard
źródło

Odpowiedzi:

16

Przed udzieleniem odpowiedzi uważam, że potrzebne są pewne wyjaśnienia. Przeanalizujmy następujące trzy linie:

source run.sh
. run.sh
./run.sh

Pierwsze dwa wiersze są dokładnie identyczne: .to tak naprawdę alias dla source. To, sourceco wykonuje skrypt powłoki w bieżącym kontekście, stąd wywołanie, aby exitopuścić powłokę.

Trzecia linia (ta, która Cię myli) nie ma jednak nic wspólnego z innymi liniami. ./run.shjest tylko ścieżką i jest taki sam jak (na przykład) /home/user/run.shlub /usr/bin/something. Zawsze pamiętaj, że polecenia w powłoce są oddzielone spacją. Tak więc w tym przypadku polecenie nie jest ., ale jest ./run.sh: oznacza to, że podpowłoka zostanie wykonana i exitbędzie działać tylko na podpowłokę.

Andrea Corbellini
źródło
5

Trzy drogi:

Możesz zawrzeć skrypt w funkcji i użyć tylko return.

#!/usr/bin/env bash
main() {
    ...
    return 1
    ...
}
main "$@"

Możesz sprawdzić, czy skrypt jest pozyskiwany przez interaktywną powłokę.

if [[ $- = *i* ]]; then
    return 1
else
    exit 1
fi

Możesz spróbować wrócić, a jeśli się nie powiedzie, wyjdź.

return 1 2>/dev/null || exit 1
geirha
źródło
Jakieś wskazówki, jak działa magiczna inkantacja $- = *i* ?
deadbeef404
@ deadbeef404 Specjalny parametr -zawiera aktualnie aktywne flagi opcji. Test sprawdza, czy -iflaga jest aktywna. Zobacz gnu.org/software/bash/manual/html_node/Special-Parameters.html
geirha
1

Pomyśl o poleceniu „source” jak w instrukcji „include”. Pobiera treść argumentu i uruchamia go tak, jakby był uruchamiany bezpośrednio. W tym przypadku twoje polecenie jest „source” z argumentem „run.sh”, a run.sh jest wykonywany dokładnie tak, jakbyś wpisał treść run.sh w linii poleceń.

Po uruchomieniu polecenia „./run.sh” polecenie „./run.sh” nie zawiera argumentów. Ponieważ ten plik jest zwykły, a nie binarny, twoja powłoka szuka interpretera w shebang ('#!' W pierwszym wierszu) i znajduje '/ bin / bash'. Więc twoja powłoka następnie uruchamia nową instancję bash, a zawartość run.sh jest uruchamiana wewnątrz tej nowej instancji.

Po pierwsze, gdy bash osiągnie komendę „exit”, jest wykonywany dokładnie tak, jakbyś wpisał go w linii poleceń. W drugim przypadku jest on wykonywany w procesie bash, który uruchomiła twoja powłoka, dlatego tylko to wystąpienie bash otrzymuje polecenie „exit”.

Gdy wpiszesz wiersz w bash, wszystko przed pierwszą spacją jest traktowane jako polecenie, a wszystko, co następuje, jest traktowane jako argumenty. Komenda '.' jest aliasem „źródła”. Kiedy biegniesz ”. run.sh „the”. jest samodzielnym poleceniem, ponieważ jest oddzielone od argumentów spacją. Po uruchomieniu polecenia „./run.sh” polecenie brzmi „./run.sh” i „.” jest częścią ścieżki względnej do run.sh z „.” reprezentujący twój bieżący folder.

pali 2345
źródło
Jeśli jesteś programistą C / C ++, który chce poprawić swoje skrypty powłoki / bash, jest to idealna odpowiedź.
Justin