Zrozumienie wbudowanych poleceń powłoki

12

W podręczniku bash jest napisane, że

Builtin commands are contained >>> within <<< the shell itself

Również ta odpowiedź stwierdza, że

A built-in command is simply a command that the shell carries out itself,
instead of interpreting it as a request to load and run some
>>> other program <<<

Kiedy biegnę compgen -bna bash 4.4, ja otrzymać listę wszystkich WBUDOWANE POLECENIA POWŁOKI. I patrz na przykład, że [a killwymienione się builtins powłoki. Ale ich rzeczywiste lokalizacje to:

/usr/bin/[
/bin/kill

Pomyślałem, że to builtinoznacza, że ​​polecenie jest wkompilowane w /bin/bashplik wykonywalny. Co mnie naprawdę dezorientuje: Proszę mnie poprawić, ale jak może być osobne polecenie builtin, skoro tak naprawdę nie jest częścią powłoki?

manifestant
źródło
1
Niektóre polecenia pierwotnie istniały jako oddzielne narzędzia. Ich obecność jest teraz zgodna ze standardem POSIX, przenośnością, a także kompatybilnością wsteczną. Powłoki implementują niektóre jako wbudowane pod kątem wydajności. Może być inny powód, ale to wszystko bez zbyt wielu szczegółów.
Sergiy Kolodyazhnyy
1
Innym powodem, o którym mogłem pomyśleć, jest to, że niektóre wbudowane polecenia są potrzebne do powłoki, na przykład execdo manipulowania deskryptorami plików i eval do oceny poleceń. Nie są potrzebne jako samodzielne polecenia
Sergiy Kolodyazhnyy

Odpowiedzi:

16

Polecenia wbudowane w powłokę są często wbudowane ze względu na wzrost wydajności, jaki to daje. Na przykład wywołanie zewnętrznego printf jest wolniejsze niż użycie wbudowanego printf.

Ponieważ niektóre narzędzia nie muszą być wbudowane, chyba że są wyjątkowe, na przykład cdsą również dostarczane jako narzędzia zewnętrzne . Dzieje się tak, aby skrypty nie uległy awarii, jeśli są interpretowane przez powłokę, która nie zapewnia wbudowanego odpowiednika.

Niektóre wbudowane powłoki dostarczają również rozszerzenia zewnętrznego równoważnego polecenia. Na printfprzykład Bash's jest w stanie to zrobić

$ printf -v message 'Hello %s' "world"
$ echo "$message"
Hello world

(wypisz do zmiennej), czego zewnętrzny /usr/bin/printfpo prostu nie byłby w stanie zrobić, ponieważ nie ma dostępu do zmiennych powłoki w bieżącej sesji powłoki (i nie może ich zmienić).

Wbudowane narzędzia również nie mają ograniczenia, że ​​ich rozszerzona linia poleceń musi być krótsza niż pewna długość. Robić

printf '%s\n' *

jest zatem bezpieczny, jeśli printfjest wbudowanym poleceniem powłoki. Ograniczenie długości wiersza poleceń wynika z execve()funkcji biblioteki C używanej do wykonania polecenia zewnętrznego. Jeśli linia poleceń i bieżące środowisko jest większe niż ARG_MAXbajty (patrz getconf ARG_MAXw powłoce), wywołanie do execve()nie powiedzie się. Jeśli narzędzie jest wbudowane w powłokę, execve()nie musi być wywoływane.

Wbudowane narzędzia mają pierwszeństwo przed narzędziami znalezionymi w $PATH. Aby wyłączyć wbudowane polecenie w bash, użyj np

enable -n printf

Istnieje krótka lista narzędzi, które muszą zostać wbudowane w powłokę (wzięte z listy specjalnych wbudowanych w standardzie POSIX )

break
colon (:)
continue
dot (.)
eval
exec
exit
export
readonly
return
set
shift
times
trap
unset

Należy je wbudować, ponieważ bezpośrednio manipulują środowiskiem i przepływem programu bieżącej sesji powłoki. Zewnętrzne narzędzie nie byłoby w stanie tego zrobić.

Co ciekawe, cdnie jest częścią tej listy, ale POSIX mówi o tym:

Ponieważ cdwpływa na bieżące środowisko wykonywania powłoki, zawsze jest dostarczane jako zwykła wbudowana powłoka. Jeśli jest wywoływany w podpowłoce lub w oddzielnym środowisku wykonywania narzędzia, takim jak jedno z następujących:

(cd /tmp)
nohup cd
find . -exec cd {} \;

nie wpływa na katalog roboczy środowiska dzwoniącego.

W związku z tym zakładam, że „specjalne” wbudowane elementy nie mogą mieć zewnętrznych odpowiedników, podczas gdy cdteoretycznie mogłyby mieć (ale niewiele by to zrobiły).

Kusalananda
źródło
IIRC, chdir/ cdbyły zewnętrznymi plikami binarnymi we wczesnych Unicach / wcześniejszych niż Unix, zanim forkzostały wprowadzone.
Xophmeister,
@Xophmeister Solaris 11.4 (beta) nadal ma /usr/bin/cd, ale tak naprawdę nie zmieni bieżącego katalogu roboczego. Jego instrukcja mówi: /usr/bin/cdnie ma wpływu na proces wywoływania, ale można go użyć do ustalenia, czy dany katalog może być ustawiony jako katalog bieżący.
Kusalananda
2
Kolejny, dość konkretny powód wbudowanych funkcji: wbudowany killjest również miły, ponieważ nie musi rozwidlać innego procesu, dobrze, jeśli osiągniesz limit liczby procesów.
derobert,
7

Jesteś (bardzo zrozumiały) zdezorientowany faktem, że niektóre wbudowane funkcje istnieją zarówno jako wbudowane, jak i jako zewnętrzne polecenia. Tak więc, chociaż masz rację, że na przykład istnieje /bin/[polecenie, nie oznacza to, że jest w nim „rzeczywista lokalizacja” /bin.

Jakiś prosty sposób na sprawdzenie tego jest prowadzony typez -aprzełącznikiem, który pokaże wszystkie dostępne instancje polecenia. W moim systemie Arch pokazuje:

$ type -a [
[ is a shell builtin
[ is /sbin/[
[ is /usr/sbin/[
[ is /usr/bin/[

Należy zauważyć, że /sbin, /usr/sbini /binsą wszystkie dowiązania wskazujące /usr/bin, więc jest tylko jeden zewnętrzny [:

$ readlink -f /usr/sbin /sbin /bin/
/usr/bin
/usr/bin
/usr/bin

Jak widać, [jest to zarówno polecenie wbudowane, jak i polecenie zewnętrzne, to samo dotyczy różnych innych poleceń wbudowanych powłoki. Nie zmienia to jednak faktu, że są one również wbudowanymi powłokami, wkompilowanymi w samą powłokę.

terdon
źródło
dlaczego dystrybucja zapewnić oddzielne polecenie zewnętrzne dla już istniejącego polecenia wewnętrznego? dlaczego się duplikują?
LoveWithMaths
1
@linuxuser niektóre z tych narzędzi są wymagane przez POSIX, i nie możesz wiedzieć, czy powłoka, której używa użytkownik, również zapewni wbudowane narzędzie. Nie myśl o nich jako o wewnętrznym poleceniu systemu operacyjnego, są to tylko wewnętrzne polecenia powłoki i powłoka może się zmieniać.
terdon
Mam teraz 1 wątpliwości, czy wewnętrzne polecenia są dostarczane przez powłokę; to kto dostarcza polecenia zewnętrzne? jak zaobserwowałem wiele poleceń, które są dostępne zarówno jako polecenia wewnętrzne, jak i zewnętrzne, ale ja ich nie zainstalowałem; więc kto zapewnia zewnętrzne polecenie? Distro zapewnia ich poprawność?
LoveWithMaths
@linuxuser zależy od polecenia i systemu operacyjnego. Na przykład w moim Arch Linux /bin/printfjest instalowany przez coreutilspakiet i /bin/killprzez util-linux.
terdon
Przepraszam, ale nadal nie jestem pewien, który z powyższych jest dostarczany przez Distro? a co z drugim, który nie jest dostarczany przez distro, to kto je zapewnia.
LoveWithMaths