cd
est un shell intégré au shell POSIX :
Si une commande simple génère un nom de commande et une liste d’arguments facultative, les actions suivantes doivent être effectuées:
- Si le nom de la commande ne contient aucune barre oblique, la première étape réussie dans la séquence suivante doit se produire:
...
- Si le nom de la commande correspond au nom d'un utilitaire répertorié dans le tableau suivant, cet utilitaire doit être appelé.
...
cd
...
- Sinon, la commande doit être recherchée en utilisant le PATH ...
Bien que cela ne dise pas explicitement qu’il doit être intégré, la spécification continue en disant: la description de cd
:
Comme cd affecte l’environnement d’exécution du shell en cours, il est toujours fourni comme un shell intégré au shell.
Du manuel bash
:
Les commandes intégrées suivantes du shell sont héritées du shell Bourne. Ces commandes sont implémentées comme spécifié par le standard POSIX.
...
cd
cd [-L|[-P [-e]]] [directory]
Je suppose que vous pourriez penser à une architecture où cd
ne doit pas nécessairement être une version intégrée. Cependant, vous devez voir ce que implique un intégré. Si vous écrivez un code spécial dans le shell pour faire quelque chose pour une commande, vous êtes sur le point d’avoir une commande intégrée. Plus vous en faites, plus il est simple d'avoir une version intégrée.
Par exemple, vous pouvez faire en sorte que le shell ait IPC pour communiquer avec des sous-processus, et il y aura un programme cd
qui vérifiera l'existence du répertoire et si vous êtes autorisé à accéder et à communiquer avec le shell. lui dire de changer son répertoire. Cependant, vous devrez vérifier si le processus de communication avec vous est un enfant (ou créer des moyens de communication spéciaux avec les enfants uniquement, tels qu'un descripteur de fichier spécial, une mémoire partagée, etc.) et si le processus est en fait exécuter le programme cd
de confiance ou autre chose. C'est une boîte entière de vers.
Ou vous pourriez avoir un programme cd
qui rend le chdir
appel système, et lance un nouveau shell avec toutes les variables d'environnement actuelles appliquées au nouveau shell, puis tue son shell parent (d'une manière ou d'une autre) une fois terminé. 1
Pire, vous pourriez même avoir un système où un processus peut modifier les environnements d'autres processus (je pense que techniquement, vous pouvez le faire avec les débogueurs). Cependant, un tel système serait très, très vulnérable.
Vous vous retrouverez à ajouter de plus en plus de code pour sécuriser de telles méthodes, et il est beaucoup plus simple de simplement en faire une méthode intégrée.
Que quelque chose est un exécutable ne l’empêche pas d’être une version intégrée. Par exemple:
echo
et test
echo
et test
sont des utilitaires POSIX ( /bin/echo
et /bin/test
). Pourtant, presque tous les shell populaires ont un echo
et test
intégré. De même, kill
est également intégré à un programme. D'autres incluent:
-
sleep
(pas aussi commun)
-
time
-
false
-
true
-
printf
Cependant, il existe des cas où une commande ne peut pas être autre chose qu'une commande intégrée. L'un d'entre eux est cd
. En règle générale, si le chemin d'accès complet n'est pas spécifié et que le nom de la commande correspond à celui d'une commande intégrée, une fonction adaptée à cette commande est appelée. Selon le shell, le comportement du fichier intégré et celui de l'exécutable peuvent différer (ceci est en particulier un problème pour echo
, qui a des comportements très différents . Si vous voulez être certain du comportement, il est préférable d'appeler l'exécutable en utilisant le chemin d'accès complet et de définir des variables comme POSIXLY_CORRECT
(même dans ce cas, il n'y a aucune garantie réelle).
Techniquement, rien ne vous empêche de fournir un système d'exploitation qui est également un shell et qui possède toutes les commandes en tant que paramètre intégré. Près de cette extrémité extrême se trouve la monolithique BusyBox . BusyBox est un binaire unique, qui (selon le nom avec lequel il est appelé) peut se comporter comme l'un des plus de 240 programmes , y compris une coque Almquist ( ash
).Si vous désactivez PATH
lors de l'exécution de BusyBox ash
, les programmes disponibles dans BusyBox vous sont toujours accessibles sans spécifier de PATH
. Ils sont proches de l’installation de shell, sauf que le shell lui-même est une sorte de bus intégré à BusyBox.
Si vous regardez la source dash
, le thread d'exécution est quelque chose comme ça (bien sûr, avec des fonctions supplémentaires impliquées lorsque des pipes et d'autres choses sont utilisées):
main
→ cmdloop
→ evaltree
→ evalcommand
evalcommand
utilise ensuite findcommand
pour déterminer quelle est la commande. S'il s'agit d'un fichier intégré, alors :
case CMDBUILTIN:
if (spclbltin > 0 || argc == 0) {
poplocalvars(1);
if (execcmd && argc > 1)
listsetvar(varlist.list, VEXPORT);
}
if (evalbltin(cmdentry.u.cmd, argc, argv, flags)) {
if (exception == EXERROR && spclbltin <= 0) {
FORCEINTON;
break;
cmdentry.u.cmd
est un struct
( struct builtincmd
), dont l'un des membres est un pointeur de fonction, avec une signature typique de main
: (int, char **)
. Les appels à la fonction evalbltin
(selon que la commande intégrée est la commande eval
) ou non) soit evalcmd
, soit ce pointeur de fonction. Les fonctions réelles sont définies dans divers fichiers sources. Par exemple, echo
est :
int
echocmd(int argc, char **argv)
{
int nonl;
nonl = *++argv ? equal(*argv, "-n") : 0;
argv += nonl;
do {
int c;
if (likely(*argv))
nonl += print_escape_str("%s", NULL, NULL, *argv++);
if (nonl > 0)
break;
c = *argv ? ' ' : '\n';
out1c(c);
} while (*argv);
return 0;
}
Tous les liens vers le code source dans cette section sont basés sur des numéros de ligne, ils peuvent donc être modifiés sans préavis.
Les systèmes
1 POSIX ont un cd
executable .
Côté note:
Il y a beaucoup d'excellents articles sur Unix & amp; Linux qui traite du comportement du shell. En particulier:
Si vous n’avez pas remarqué de modèle dans les questions listées jusqu’à présent, presque toutes impliquent Stéphane Chazelas .