Jaka jest różnica między uruchomieniem „bash script.sh” i „./script.sh”?

42

Jeśli skrypt.sh jest po prostu czymś typowym

#!/bin/bash
echo "Hello World!"

Czy istnieje preferowany sposób uruchomienia skryptu? Myślę, że najpierw musisz go chmod, aby stał się wykonywalny?

użytkownik72136
źródło

Odpowiedzi:

56

W przypadku konkretnego skryptu w obu przypadkach będzie działać, z wyjątkiem tego, że ./script.shwymaga wykonania i czytelnych bitów, a bash script.shjedynie wymaga bitu czytelnego.


Przyczyna różnicy wymagań dotyczących uprawnień leży w sposobie ładowania programu, który interpretuje skrypt:

  • ./script.sh sprawia, że ​​powłoka uruchamia plik tak, jakby był zwykłym plikiem wykonywalnym.

Powłoka sama się rozwidla i używa wywołania systemowego (np. execve), Aby system operacyjny wykonał plik w rozwidlonym procesie. System operacyjny sprawdzi uprawnienia do pliku (stąd należy ustawić bit wykonawczy) i prześle żądanie do programu ładującego , który spojrzy na plik i określi sposób jego wykonania. W Linuksie skompilowane pliki wykonywalne zaczynają się od magicznej liczby ELF , podczas gdy skrypty zaczynają się od #!( hashbang ). Nagłówek hashbang oznacza, że ​​plik jest skryptem i musi zostać zinterpretowany przez program określony po haszu. To pozwala samemu skryptowi powiedzieć systemowi, jak interpretować skrypt.

Za pomocą skryptu moduł ładujący program uruchomi się /bin/bashi przekaże ./script.sh jako argument wiersza polecenia.

  • bash script.shsprawia, że ​​twoja powłoka działa bashi przekazuje script.shjako argument wiersza poleceń

System operacyjny się załaduje bash(nawet nie patrząc script.sh, ponieważ jest to tylko argument wiersza poleceń). Utworzony bashproces zinterpretuje następnie, script.shponieważ został przekazany jako argument wiersza polecenia. Ponieważ script.shjest odczytywany tylko bashjako zwykły plik, bit wykonania nie jest wymagany.


Zalecam ./script.shjednak użycie , ponieważ możesz nie wiedzieć, jakiego interpretera wymaga skrypt. Pozwól więc programowi ładującemu ustalić to dla Ciebie.

SkyDan
źródło
3
Jeśli bit wykonywalny nie jest ustawiony, możesz również uruchomić skrypt, wykonując polecenie „./script.sh”
Dog eat cat world
1
@Dog Masz rację. Kropka jest skrótem do wbudowanego polecenia „source”, które uruchamia skrypt w bieżącym procesie bash. Wymagany jest więc tylko czytelny bit.
SkyDan
5
@Dogeatcatworld, chociaż jest to prawdą, bieganie . ./script.shto nie to samo, co bash script.sh(lub ./script.sh. Rozważmy skrypt #!/usr/bin/python -V<nowa linia> print test.
Casey
12
Uważaj, że uzyskanie skryptu może spowodować zanieczyszczenie sesji interaktywnej. Na przykład, jeśli skrypt zmieni zmienną środowiskową PATH, zmiana ta wpłynie na polecenia uruchamiane po źródle. To podejście powinno być naprawdę zarezerwowane dla sytuacji, w których zależy się od efektów ubocznych (skrypty konfiguracji środowiska i tym podobne). W innych sytuacjach, w których nie można zmienić uprawnień, najbezpieczniejszym rozwiązaniem jest uruchomienie polecenia w wierszu shebang, a następnie nazwa skryptu.
ctt
6
Zauważ, że jeśli źródłowy skrypt znajduje się w bieżącym katalogu, nie musisz używać ./ ; po prostu powiedz . script.sh. Ale zgadzam się z ludźmi, którzy zniechęcają do używania .polecenia w skryptach, które nie miały być wywoływane w ten sposób. Dziwię się, że nikt o tym nie wspominał, jeśli skrypt zawiera exitpolecenia, a Ty je pozyskasz, może Cię wylogować. Mniej poważnym problemem byłoby, gdyby skrypt działał cd, ponieważ wpłynęłoby to również na powłokę nadrzędną (interaktywną).
Scott
18

bash script.shwywołuje skrypt bezpośrednio za pomocą bash.
./script.shużywa shebang, #!/bin/bashaby określić sposób wykonania.

Jeśli naprawdę chcesz wiedzieć, który plik binarny jest wykonywany, możesz zrobić to bash script.shz which bash.

W twoim przykładzie nie ma to znaczenia. Tak, musisz chmod +x script.shbyć w stanie wykonać go bezpośrednio przez ./script.sh.

xx4h
źródło
2
Cóż, nie ma znaczenia, zakładając, że /bin/bashjest to pierwszy bashw twoim $PATH.
cjm
Masz rację. A shebang #!/bin/bashdziała tylko, jeśli jest/bin/bash
xx4h
Bash (wersja 4.2.37) w moim systemie wykonuje skrypty nawet bez ustawionego bitu wykonania. Dlaczego uważasz, że bit wykonania jest wymagany?
SkyDan
Tak, bit wykonania jest potrzebny tylko przez wywołanie przez ./script.sh.
xx4h
4

Utwórz plik Delete_Self.sh w następujący sposób:

 #!/bin/rm

 echo I am still here!

Uruchom ten skrypt, a sh Delete_Self.shzobaczysz „Nadal tu jestem!” odbiło się echem.

Spraw, by był wykonywalny i uruchom go, ponieważ ./Delete_Self.shzobaczysz, że nic nie jest odbijane ponownie, gdy Delete_Self.shsam plik zniknie.

Różnica polega na tym, że:

  • bash script.shzignoruje #! wiersz, ponieważ jako program do uruchamiania script.sh określono bash.
  • ./script.shprzeczyta #! wiersz, aby określić program do uruchomienia script.sh.
David
źródło
+1 za ładny przykład
ThisaruG
1

Oprócz innych odpowiedzi przydatna jest znajomość różnicy między uruchomieniem skryptu za pomocą ./script.sh(i) i źródła ./script.sh(ii) - Wersja (i) tworzy nową powłokę, w której można uruchomić polecenie, podczas gdy (ii) uruchamia go w bieżąca powłoka - która może być obowiązkowa, jeśli plik wykonywalny zmienia zmienne środowiskowe, które należy zachować po wyjściu z pliku wykonywalnego. Na przykład, aby aktywować środowisko conda Pythona, należy zastosować:

source activate my_env

Uwaga: Inną alternatywą source, którą możesz napotkać, jest .wbudowane, tj

. activate my_env
einonm
źródło