cd
est un shell shell mandaté par POSIX:
Si une commande simple donne un nom de commande et une liste facultative d'arguments, les actions suivantes doivent être effectuées:
- Si le nom de la commande ne contient aucune barre oblique, la première étape réussie de 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 à l'aide du CHEMIN ...
Bien que cela ne dise pas explicitement qu'il doit être intégré, la spécification continue dans la description decd
:
Puisque cd affecte l'environnement d'exécution du shell actuel, il est toujours fourni en tant que shell standard intégré.
Du bash
manuel :
Les commandes intégrées du shell suivantes sont héritées du Bourne Shell. Ces commandes sont implémentées comme spécifié par la norme POSIX.
...
cd
cd [-L|[-P [-e]]] [directory]
Je suppose que vous pourriez penser à une architecture qui cd
ne doit pas nécessairement être intégrée. Cependant, vous devez voir ce qu'implique un intégré. Si vous écrivez du code spécial dans le shell pour faire quelque chose pour une commande quelconque, vous vous approchez d'avoir une fonction intégrée. Plus vous en faites, mieux c'est d'avoir simplement un intégré.
Par exemple, vous pouvez demander au shell d'avoir IPC pour communiquer avec les sous-processus, et il y aurait un cd
programme qui vérifierait l'existence du répertoire et si vous avez l'autorisation d'y accéder, puis communique avec le shell pour lui dire de changer son annuaire. Cependant, vous devrez ensuite 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 cd
programme de confiance ou autre chose. C'est toute une boîte de vers.
Ou vous pourriez avoir un cd
programme qui fait l' chdir
appel système, et le démarre un nouveau shell avec toutes les variables d'environnement actuelles appliquées au nouveau shell, puis tue son shell parent (en quelque sorte) 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 des 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 ces méthodes, et il est considérablement plus simple d'en faire simplement un intégré.
Que quelque chose soit un exécutable ne l'empêche pas d'être intégré. Exemple:
echo
et test
echo
et test
sont des utilitaires mandatés par POSIX ( /bin/echo
et /bin/test
). Pourtant, presque tous les shell populaires ont un intégré echo
et test
. De même, kill
est également intégré qui est disponible en tant que programme. Parmi les autres:
sleep
(pas aussi commun)
time
false
true
printf
Cependant, il existe certains cas où une commande ne peut pas être autre chose qu'une fonction intégrée. L'un d'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'un code intégré, une fonction adaptée à cette commande est appelée. Selon le shell, le comportement du builtin et celui de l'exécutable peuvent différer (c'est particulièrement un problème pourecho
, 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 complet et définissez des variables comme POSIXLY_CORRECT
(même alors, il n'y a pas de réelle garantie).
Techniquement, rien ne vous empêche de fournir un système d'exploitation qui est également un shell et a toutes les commandes en tant que intégré. Près de cette extrémité extrême se trouve la BusyBox monolithique . BusyBox est un binaire unique qui (selon le nom avec lequel il est appelé) peut se comporter comme n'importe lequel des 240 programmes , y compris un shell Almquist ( ash
). Si vous désactivez PATH
pendant l'exécution de BusyBox ash
, les programmes disponibles dans BusyBox sont toujours accessibles sans spécifier a PATH
. Ils se rapprochent d'être des commandes intégrées au shell, sauf que le shell lui-même est une sorte de commande intégrée à BusyBox.
Si vous regardez la dash
source, le thread d'exécution est quelque chose comme ça (bien sûr, avec des fonctions supplémentaires impliquées lorsque des tuyaux et d'autres choses sont utilisées):
main
→ cmdloop
→ evaltree
→evalcommand
evalcommand
utilise ensuite findcommand
pour déterminer la commande. S'il s'agit d'une fonction intégrée, 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 un des membres est un pointeur de fonction avec une signature typique de main
: (int, char **)
. La evalbltin
fonction appelle (selon que la eval
commande intégrée est la commande ou non) evalcmd
ou ce pointeur de fonction. Les fonctions réelles sont définies dans divers fichiers source. echo
, par exemple, c'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 un numéro de ligne, ils peuvent donc changer sans préavis.
1 Les systèmes POSIX ont un cd
exécutable .
Note latérale:
Il y a beaucoup d'excellents articles sur Unix et Linux qui traitent du comportement du shell. En particulier:
Si vous n'avez pas remarqué de tendance dans les questions énumérées jusqu'à présent, presque toutes impliquent Stéphane Chazelas .
type
commande