Ponieważ plik nie należy do żadnego z typów plików wykonywalnych rozpoznawanych przez system i przy założeniu, że masz uprawnienia do wykonania tego pliku, execve()
wywołanie systemowe zwykle kończy się niepowodzeniem z błędem ENOEXEC
( nie wykonywalnym ).
To, co się wtedy stanie, zależy od aplikacji i / lub funkcji bibliotecznej użytej do wykonania polecenia.
Może to być na przykład powłoka, funkcja execlp()
/ execvp()
libc.
Większość innych aplikacji będzie używać jednej z tych aplikacji po uruchomieniu polecenia. Będą wywoływać powłokę na przykład za pomocą system("command line")
funkcji libc, która zwykle wywołuje w sh
celu parsowania tej linii poleceń (której ścieżkę można określić w czasie kompilacji (jak /bin/sh
vs /usr/xpg4/bin/sh
w Solarisie)) lub wywołuje powłokę przechowywaną $SHELL
przez siebie jak vi
z jego !
poleceniem lub xterm -e 'command line'
wieloma innymi poleceniami ( su user -c
zamiast tego wywoła powłokę logowania użytkownika $SHELL
).
Zasadniczo plik tekstowy bez shebang, który się nie zaczyna, #
jest uważany za sh
skrypt. Które sh
to będzie się różnić.
execlp()
/ execvp()
, po execve()
powrocie ENOEXEC
zwykle wywołuje sh
na nim. W przypadku systemów, które mają więcej niż jeden, sh
ponieważ mogą być zgodne z więcej niż jednym standardem, co sh
zwykle określa się w czasie kompilacji (aplikacji używającej execvp()
/ execlp()
przez połączenie innego obiektu blob kodu, który odnosi się do innej ścieżki sh
). Na przykład w /usr/xpg4/bin/sh
systemie Solaris będzie to (standard, POSIX sh
) lub /bin/sh
(powłoka Bourne'a (przestarzała powłoka) w systemie Solaris 10 i starszych wersjach, ksh93 w systemie Solaris 11).
Jeśli chodzi o muszle, istnieje wiele odmian. bash
, AT&T ksh
, powłoka Bourne'a zazwyczaj interpretuje sam skrypt (w procesie potomnym, o ile nie exec
jest używany) po symulacji a execve()
, czyli nieuzbrojonej wszystkich nieobsługiwanych zmiennych, zamykając wszystkie fds close-on-exec, usuwając wszystkie niestandardowe pułapki, aliasy, funkcje ... ( bash
zinterpretuje skrypt w sh
trybie). yash
wykona się ( tak sh
jak argv[0]
w sh
trybie), aby go zinterpretować.
zsh
, pdksh
, ash
Opartych powłoki zazwyczaj wywołania sh
(ścieżka, która określona w czasie kompilacji).
Dla csh
i tcsh
(i sh
niektórych wczesnych BSD), jeśli pierwszym znakiem pliku jest #
, to wykonają się, aby go zinterpretować, i w sh
przeciwnym razie. To sięga czasów sprzed shebang, w których csh
rozpoznawano #
jako komentarze, ale nie powłokę Bourne'a, więc #
była to wskazówka, że był to skrypt csh.
fish
(przynajmniej wersja 2.4.0), po prostu zwraca błąd, jeśli się execve()
nie powiedzie (nie próbuje traktować go jako skryptu).
Niektóre powłoki (jak bash
AT&T ksh
) najpierw spróbują heurystycznie ustalić, czy plik prawdopodobnie ma być skryptem, czy nie. Może się więc okazać, że niektóre powłoki odmówią wykonania skryptu, jeśli w pierwszych kilku bajtach ma znak NUL.
Zauważ też, że jeśli execve()
nie powiedzie się ENOEXEC, ale plik ma linię shebang, niektóre powłoki próbują sami interpretować tę linię shebang.
Oto kilka przykładów:
- Kiedy
$SHELL
jest /bin/bash
, xterm -e 'myscript with args'
będzie myscript
interpretowane przez bash
w sh
trybie. Podczas gdy xterm -e myscript with args
, xterm
użyje, execvp()
więc skrypt zostanie zinterpretowany przez sh
.
su -c myscript
na Solarisie 10, gdzie root
powłoka logowania jest /bin/sh
i /bin/sh
jest powłoką Bourne'a, zostanie myscript
zinterpretowana przez powłokę Bourne'a.
/usr/xpg4/bin/awk 'BEGIN{system("myscript")'
na Solarisie 10 będzie interpretowany przez /usr/xpg4/bin/sh
(to samo dla /usr/xpg4/bin/env myscript
).
find . -prune -exec myscript {} \;
na Solarisie 10 (używanie execvp()
) będzie interpretowane /bin/sh
nawet przez /usr/xpg4/bin/find
, nawet w środowisku POSIX (błąd zgodności).
csh -c myscript
będzie interpretowany przez, csh
jeśli zacznie od #
, w sh
przeciwnym razie.
Podsumowując, nie możesz być pewien, która powłoka zostanie użyta do interpretacji tego skryptu, jeśli nie wiesz jak i przez co zostanie on wywołany.
W każdym razie read -p
jest to bash
tylko składnia, więc upewnij się, że skrypt jest interpretowany przez bash
(i unikaj tego mylącego .sh
rozszerzenia). Albo znasz ścieżkę bash
pliku wykonywalnego i użyj:
#! /path/to/bash -
read -p ...
Lub możesz polegać na $PATH
wyszukiwaniu bash
pliku wykonywalnego (zakładając, że bash
jest zainstalowany), używając:
#! /usr/bin/env bash
read -p ...
( env
jest prawie wszechobecny w /usr/bin
). Alternatywnie możesz ustawić kompatybilność POSIX + Bourne. W takim przypadku możesz użyć /bin/sh
. Wszystkie systemy będą miały /bin/sh
. W większości z nich będzie (w przeważającej części) kompatybilny z POSIX, ale możesz od czasu do czasu znaleźć tam powłokę Bourne'a.
#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"