Comprendre les commandes intégrées du shell

12

Dans le manuel bash , il est écrit que

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

En outre, cette réponse indique que

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 <<<

Quand je cours compgen -bsur bash 4.4, je reçois une liste de toutes les commandes SHELL. Je vois par exemple cela [et killsont répertoriés comme étant des commandes intégrées au shell. Mais leurs emplacements réels sont:

/usr/bin/[
/bin/kill

Je pensais que builtincela signifie que la commande est compilée dans l' /bin/bashexécutable. Alors qu'est-ce qui m'embrouille vraiment: Veuillez me corriger, mais comment une commande distincte peut-elle être une builtin, alors qu'elle ne fait en fait pas partie du shell?

manifestant
la source
1
Certaines commandes existaient à l'origine en tant qu'utilitaires distincts. Leur présence concerne désormais la conformité aux normes POSIX, la portabilité ainsi que la compatibilité descendante. Les shells implémentent certains comme intégrés pour les performances. Il peut y avoir une autre raison, mais c'est à peu près tout sans trop de détails.
Sergiy Kolodyazhnyy
1
Une autre raison pour laquelle je pourrais penser, c'est parce que certaines commandes intégrées sont nécessaires pour le shell spécifiquement, comme execpour manipuler les descripteurs de fichiers et eval pour l'évaluation des commandes. Ils ne sont pas nécessaires en tant que commandes autonomes
Sergiy Kolodyazhnyy

Réponses:

16

Les commandes intégrées au shell sont souvent intégrées en raison de l'augmentation des performances que cela donne. Par exemple, appeler l' externe printf est plus lent que d'utiliser le intégré printf.

Étant donné que certains utilitaires n'ont pas besoin d'être intégrés, à moins qu'ils ne soient spéciaux, comme cd, ils sont également fournis en tant qu'utilitaires externes . Ceci afin que les scripts ne se cassent pas s'ils sont interprétés par un shell qui ne fournit pas d'équivalent intégré.

Certains éléments intégrés du shell fournissent également des extensions à la commande externe équivalente. Bash printf, par exemple, est capable de faire

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

(imprimer dans une variable) ce que l'externe /usr/bin/printfne pourrait tout simplement pas faire car il n'a pas accès aux variables shell dans la session shell actuelle (et ne peut pas les changer).

Les utilitaires intégrés n'ont pas non plus la restriction que leur ligne de commande étendue doit être plus courte qu'une certaine longueur. Faire

printf '%s\n' *

est donc sûr si printfest une commande intégrée au shell. La restriction de la longueur de la ligne de commande provient de la execve()fonction de bibliothèque C utilisée pour exécuter une commande externe. Si la ligne de commande et l'environnement actuel sont plus grands que les ARG_MAXoctets (voir getconf ARG_MAXdans le shell), l'appel à execve()échouera. Si l'utilitaire est intégré au shell, il execve()n'est pas nécessaire de l'appeler.

Les utilitaires intégrés ont priorité sur les utilitaires trouvés dans $PATH. Pour désactiver une commande intégrée dans bash, utilisez par exemple

enable -n printf

Il y a une courte liste d'utilitaires qui doivent être intégrés dans un shell (extrait de la liste des standards spéciaux du standard POSIX )

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

Ceux-ci doivent être intégrés car ils manipulent directement l'environnement et le flux de programme de la session shell actuelle. Un utilitaire externe ne serait pas en mesure de le faire.

Fait intéressant, cdne fait pas partie de cette liste, mais POSIX dit ce qui suit à ce sujet:

Comme cdaffecte l'environnement d'exécution du shell actuel, il est toujours fourni en tant que shell intégré standard. S'il est appelé dans un environnement d'exécution de sous-shell ou d'utilitaire distinct, tel que l'un des éléments suivants:

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

cela n'affecte pas le répertoire de travail de l'environnement de l'appelant.

Je suppose donc que les incorporés "spéciaux" ne peuvent pas avoir d'homologues externes, alors cdqu'en théorie ils auraient pu (mais cela ne ferait pas grand-chose).

Kusalananda
la source
IIRC, chdir/ cdétaient des binaires externes dans les tout premiers Unices / pré-Unix avant d' forkêtre introduits.
Xophmeister
@Xophmeister Solaris 11.4 (beta) a toujours /usr/bin/cd, mais il ne changera pas réellement le répertoire de travail actuel. Son manuel dit: /usr/bin/cdn'a aucun effet sur le processus d'appel mais peut être utilisé pour déterminer si un répertoire donné peut être défini comme répertoire courant.
Kusalananda
2
Une autre raison, plutôt spécifique, des buildins: builtin killest également agréable car il n'a pas besoin de bifurquer un autre processus, bien si vous avez atteint la limite de votre nombre de processus.
derobert
7

Vous êtes (tout à fait compréhensible) confus par le fait que certains buildins existent à la fois en tant que buildins et en tant que commandes externes. Donc, bien que vous ayez raison, par exemple, qu'il existe une /bin/[commande, cela ne signifie pas que son «emplacement réel» est /bin.

Tout moyen facile de tester cela est d'exécuter typeavec le -acommutateur qui affichera toutes les instances disponibles d'une commande. Sur mon système Arch, cela montre:

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

Notez que /sbin, /usr/sbinet que /bintous les liens symboliques pointent vers /usr/bin, il n'y a donc qu'un seul externe [:

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

Comme vous pouvez le voir, il [s'agit à la fois d'une commande intégrée et d'une commande externe, et il en va de même pour diverses autres commandes intégrées de shell. Cependant, cela ne change pas le fait qu'il s'agit également de commandes intégrées au shell, compilées dans le shell lui-même.

terdon
la source
pourquoi distro. fournir une commande externe distincte pour une commande interne déjà existante? pourquoi font-ils double emploi?
LoveWithMaths
1
@linuxuser certains de ces utilitaires sont requis par POSIX, et vous ne pouvez pas savoir si le shell utilisé par un utilisateur fournira également une fonction intégrée. Ne les considérez pas comme une commande interne du système d'exploitation, ce ne sont que des commandes internes du shell, et le shell peut changer.
terdon
J'ai maintenant 1 doute, si les commandes internes sont fournies par shell; alors qui fournit les commandes externes? comme j'ai observé de nombreuses commandes disponibles aussi bien en interne qu'en externe, mais je les ai explicitement installées; alors qui fournit la commande externe? Distro les fournit correctement?
LoveWithMaths
@linuxuser dépend de la commande et du système d'exploitation. Par exemple, sur mon Arch Linux, /bin/printfest installé par le coreutilspackage et /bin/killpar util-linux.
terdon
Je suis désolé mais je ne suis toujours pas clair, lequel des éléments ci-dessus est fourni par la distribution? et que dire de l'autre qui n'est pas fourni par la distribution alors qui le fournit.
LoveWithMaths