Uruchamianie skryptu powłoki, gdy „/ bin / sh” wskazuje na „/ bin / bash”

11

W tym pytaniu przeczytałem :

bash obsługuje przełącznik --posix, co czyni go bardziej zgodnym z POSIX. Próbuje również naśladować POSIX, jeśli zostanie wywołany jako sh .

Powyższy cytat zakłada, że /bin/shjest to link, który wskazuje /bin/bash.

Ale nie do końca rozumiem, co oznacza „wywoływany jako sh” .


Powiedz, że mam następujący skrypt o nazwie „script.sh”:

#!/bin/bash
echo "Hello World"

Proszę powiedzieć mi w każdym z poniższych przypadków, czy skrypt będzie uruchamiany w bashtrybie normalnym , czy w trybie POSIX (załóżmy, że wykonałem następujące polecenia w uruchomionym terminalu bash):

  1. sh script.sh
  2. bash script.sh
  3. ./script.sh

Teraz powiedz, że mam następujący skrypt, który nazywa się „script.sh” (który jest podobny do powyższego skryptu, ale bez shebang):

echo "Hello World"

Proszę powiedzieć mi w każdym z poniższych przypadków, czy skrypt będzie uruchamiany w bashtrybie normalnym , czy w trybie POSIX (załóżmy, że wykonałem następujące polecenia w uruchomionym terminalu bash):

  1. sh script2.sh
  2. bash script2.sh
  3. ./script2.sh
użytkownik269904
źródło

Odpowiedzi:

19

Tylko przypadki 1 i 4 będą działać w trybie POSIX (zakładając, że shjest to bash, a nie jakaś inna implementacja sh). Każdy przypadek, który jawnie wywołuje bashbez --posix, nie będzie, czy to z shebang, czy nie. Każdy przypadek, który wyraźnie shwywoła, będzie. Shebang jest używany tylko wtedy, gdy żadna powłoka nie została już wyraźnie uruchomiona dla skryptu.

Przypadek 6, jeśli twój terminal jest uruchomiony bash, nie będzie działał w trybie POSIX, a Bash wywoła go przy użyciu samego siebie. Gdyby twój terminal zamiast tego działał zsh, przypadek 6 również działałby w trybie POSIX. POSIX jest niejednoznaczny co do tego, co powinno się zdarzyć w takim przypadku , a Bash i zsh dokonali tam różnych wyborów. Bash wywołuje skrypt za pomocą samego siebie, podczas gdy zsh używa sh(cokolwiek by się nie stało). Inne pociski również różnią się w tym punkcie.


Jednym prostym sposobem na określenie, w jakim trybie się znajdujesz, jest utworzenie skryptu:

kill -SIGHUP

co zakończy się niepowodzeniem z błędem w trybie POSIX , ale poda instrukcje użytkowania killpoza nim. Jest to łatwe rozróżnienie i działa w szerokim zakresie wersji Bash, sięgając wstecz, na ile możesz się natknąć.

Michael Homer
źródło
3
Są inne rzeczy, które zmuszą bashdo uruchomienia w trybie POSIX, takie jak POSIXLY_CORRECTzmienna środowiskowa lub SHELLOPTS=posix.
Stéphane Chazelas,
1
[ -o posix ]jest bardziej oczywistym sposobem sprawdzenia, czy działasz w trybie posix w bash (nie w innych powłokach (z wyjątkiem yash), więc nie chciałbyś tego robić w shskrypcie). POSIXLY_CORRECT=1 bash -c '[ -o posix ] && echo yes'wyjścia yes`
Stéphane Chazelas
2
W przypadku 6 bash wywołuje sam skrypt w trybie POSIX, gdy sam jest w trybie POSIX, zgodnie z wymaganiami POSIX. POSIX nie określa mechanizmu she-bang, a 6 to jedyny sposób POSIX-a na wykonywanie skryptów wykonywalnych i jest on wyraźnie określony (w środowiskach POSIX skrypt powinien być interpretowany przez zgodny program narzędziowy sh).
Stéphane Chazelas
8

„Wywołany jako” odnosi się do wszystkiego, co proces uruchamiający Bash umieszcza w argumencie wiersza poleceń „zero” argv[0].

Kiedy program jest uruchamiany z exec*()syscallami , tak naprawdę nie znają nazwy pliku binarnego zawierającego program, ale zamiast tego proces wywoływania może umieścić tam, co chce. Zwykle oczywiście nazwa jest pobierana z systemu plików, więc jeśli uruchomisz /bin/sh, to właśnie tam zostanie umieszczona. A jeśli /bin/shjest to Bash, nie musi to być dowiązanie symboliczne, może to być dowiązanie twarde lub po prostu kolejna kopia programu powłoki.

Jako przykład ustawienia „nazwy programu”, execpolecenie Bash może ustawić argument zerowy z -aopcją. (Możemy zrobić to samo z Perlem lub bezpośrednio z C itp.)

Oto mynameprosty program C, który po prostu wypisuje swój zerowy argument, nazwę, którą widzi:

$ ./myname 
I am ./myname
$ (exec -a something ./myname )
I am something
$ mv ./myname somename
$ ln -s somename othername
$ ./somename 
I am ./somename
$ ./othername
I am ./othername

Źródło:

#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("I am %s\n", argv[0]);
    return 0;
}

Ale, aby odpowiedzieć na ponumerowane pytania ...

(1 i 4) bieganie sh somescripturuchomi wszystko, co shjest na twoim PATH, prawdopodobnie, /bin/shale prawdopodobnie coś takiego/usr/xpg4/bin/sh .

  • Jeśli jest to Bash, działa w trybie POSIX, ponieważ widzi nazwę sh.
  • Jeśli jest to powłoka Z lub Korn, również widzi nazwę sh, ale działa w trybie „kompatybilnym z SH”, który ma na celu być kompatybilnym z powłoką Bourne'a i jest nieco inny niż tryb zgodny z POSIX w obu tych powłokach .
  • Może to być skorupa Almquista, rzeczywista skorupa Bourne'a lub oczywiście coś innego.

(2 i 5) Bieganie bash somescriptbędzie działało w zwykłym trybie Bash (znowu, oczywiście zależy to od tego, co bashmasz PATH).

(3) Tutaj nazwa skryptu jest podawana bezpośrednio do wywołania systemowego zamiast pliku programu. Jądro czyta wiersz hashbanga i używa go do uruchomienia skryptu.

(6) To jest złożony. Jest podobny do (3), ale wywołanie systemowe do uruchomienia programu kończy się niepowodzeniem ( ENOEXEC (Exec format error)), ponieważ nie ma linii mieszania. Co dzieje się dalej, zależy od tego, czy powłoka że używasz jest się w trybie POSIX. POSIX wymaga, aby powłoka zgodna z POSIX zachowywała się w określony sposób w odpowiedzi na ENOEXEC. Istnieje jednak pewien margines swobody w „poleceniu równoważnym wywołaniu powłoki”, co oznacza, że ​​różne powłoki wykonują różne czynności.

  • Powłoka Bourne Again ponownie uruchamia się w tym samym trybie z nazwą skryptu jako pierwszego argumentu wiersza poleceń. W trybie zgodnym z POSIX działa oczywiście w trybie zgodnym z POSIX, spełniając w ten sposób wymóg POSIX dotyczący wywołania powłoki zgodnej z POSIX.
  • Powłoka Z, powłoka Almquist i powłoka Korna działają /bin/shz nazwą skryptu wstawioną przed innymi argumentami jako pierwszym argumentem wiersza poleceń. Powłoka Z, powłoka Almquista i powłoka Korna (próbują) wywołać powłokę zgodną z POSIX, zakładając, że /bin/shprogram jest jednym.
ilkkachu
źródło
Czy możesz podzielić się kodem źródłowym tego programu w języku C ..
GypsyCosmonaut
int main(int argc, char *argv[]){printf("I am %s\n",argv[0]);}
Stig Hemmer
To prawie wszystko.
ilkkachu
4

Wykonywana powłoka jest albo wywoływana w wierszu poleceń, albo w shebang (jeśli wiersz poleceń tego nie określa).

Tak więc wersje 1 i 4 będą działać z sh, 2 i 5 z bash, a 6 może nie działać, jeśli używasz sh (i niektórych innych) interaktywnie. Bash zaczyna skrypt. Ksh też. Zsh zaczyna to jako sh.

Tylko te, które zostały uruchomione, shbędą korzystać z opcji posix, jeśli bash jest połączony z /bin/sh.

Dodaj ten wiersz do skryptu, aby wykryć, czy jest uruchomiona jakaś wersja bash ksh lub zsh:

echo "Hello World $BASH_VERSION $KSH_VERSION $ZSH_VERSION"
Izaak
źródło