J'ai essayé which cd
et il n'a pas donné de chemin mais a renvoyé le code de sortie 1 (vérifié avec echo $?
). Le coreutil cd
lui-même fonctionne, donc l'exécutable devrait être là, non? J'ai également exécuté un find
pour cd
, mais aucun fichier exécutable n'a été affiché. Comment est-il mis en œuvre alors?
Mettre à jour:
Je ne sais pas si je devrais poser cette question dans un autre post, mais comme je pense que c'est bien ici, j'élargis (?) Le post ... Donc, la réponse était assez simple, il n'y a pas d'exécutable pour cela - car c'est a intégré - Mais j'ai trouvé des éléments intégrés (bash Shell dans Fedora) avoir les fichiers exécutables! Donc, intégré -> aucun exécutable n'est pas correct, je suppose? Peut-être une réponse expliquant ce que sont les commandes intégrées (commandes intégrées?), Ce qui est le problème ici, plutôt que de se concentrer davantage sur cd
... Quelques bons liens postés précédemment indiquent que les instructions intégrées ne sont pas des programmes ... alors que sont-elles? Comment travaillent-ils? S'agit-il uniquement de fonctions ou de threads du shell?
cd
ne peut pas être un exécutableDans un shell, cd
est utilisé pour "aller dans un autre répertoire", ou plus formellement, pour changer le répertoire de travail actuel (CWD). Il est impossible d'implémenter cela en tant que commande externe:
Le répertoire de travail actuel est le répertoire utilisé pour interpréter les chemins relatifs afin d'obtenir un chemin complet pouvant être utilisé pour accéder aux fichiers. Les chemins relatifs sont utilisés dans de nombreux endroits et l'interprétation d'un processus ne doit pas influencer un autre processus.
Pour cette raison, chaque processus a son propre répertoire de travail actuel.
cd
concerne la modification du répertoire de travail actuel du processus Shell, par exemple bash
.
S'il s'agissait d'une commande externe, un exécutable dans le chemin, son exécution créerait un processus avec son propre répertoire de travail, sans influencer celui du Shell en cours. Même si la commande externe change de répertoire, cette modification disparaît à la fin du processus externe.
Il n’a donc aucun sens de lancer une commande externe pour la tâche cd
. La commande cd
doit appliquer une modification au processus Shell en cours d'exécution.
Pour ce faire, il s’agit d’une "commande intégrée" du shell.
Les commandes intégrées sont des commandes qui se comportent de manière similaire aux commandes externes, mais sont implémentées dans le shell (donc, cd
ne fait pas partie des coreutils). Cela permet à la commande de modifier l'état du shell lui-même, dans ce cas, d'appeler chdir()
see (voir man 2 chdir
);
which
Maintenant, la réponse à la question du titre est simple:
La commande exécutable which
ne peut pas nous dire que cd est une commande intégrée car une commande exécutable ne sait rien des opérations intégrées.
type -a
Au lieu de which
, vous pouvez utiliser type -a
; Il peut voir les commandes exécutables et les commandes intégrées; De plus, il voit des alias et des fonctions - également implémentés dans le shell:
$ type -a cd
cd is a Shell builtin
$ type -a type
type is a Shell builtin
$ type -a which
which is /usr/bin/which
which is /bin/which
cd
est un POSIX-mandated Intégré dans le shell:
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 pas de barre oblique, la première étape réussie de la séquence suivante doit avoir lieu:
...
- 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 de PATH ...
Bien que cela ne dise pas explicitement que cela doit être intégré, la spécification ajoute: la description de cd
:
Etant donné que cd affecte l’environnement d’exécution du shell actuel, il est toujours fourni en tant qu’intégré du shell.
Depuis le bash
manual :
Les commandes intégrées Shell suivantes sont héritées du Bourne Shell. 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 intégré. Cependant, vous devez voir ce qu’implique une fonction intégrée. Si vous écrivez un code spécial dans le shell pour faire quelque chose pour une commande quelconque, vous êtes sur le point d'avoir une commande intégrée. Plus vous en faites, mieux c'est d'avoir simplement une fonction intégrée.
Par exemple, vous pouvez demander au shell d’avoir IPC pour communiquer avec les sous-processus, et il y aurait un programme cd
qui vérifierait l’existence du répertoire et si vous disposiez de l’autorisation d’y accéder, puis de communiquer avec le Shell pour lui dire de changer de répertoire. Cependant, vous devrez ensuite vérifier si le processus qui communique avec vous est un enfant (ou créer un moyen de communication spécial uniquement avec les enfants, tel qu'un descripteur de fichier spécial, la mémoire partagée, etc.), et si le processus est réellement exécuter le programme cd
de confiance ou autre chose. C'est une boîte de Pandore.
Ou vous pourriez avoir un programme cd
qui effectue l'appel système chdir
, et démarre un nouveau shell avec toutes les variables d'environnement actuelles appliquées au nouveau shell, puis élimine son shell parent (en quelque sorte) lorsque vous avez terminé. 1
Pire, vous pourriez même avoir un système où un processus peut modifier les environnements d'autres processus (techniquement, je pense que vous pouvez le faire avec des débogueurs). Cependant, un tel système serait très très vulnérable.
Vous serez amené à ajouter de plus en plus de code pour sécuriser de telles méthodes, et il est beaucoup plus simple de simplement en faire un outil intégré.
Que quelque chose soit un exécutable n'empêche pas qu'il soit intégré. Exemple:
echo
et test
echo
et test
sont des utilitaires commandés par POSIX (/bin/echo
et /bin/test
). Pourtant, presque tous les Shell populaires ont un echo
et un test
intégrés. De même, kill
est également intégré et disponible en tant que programme. Parmi les autres:
sleep
(pas aussi commun)time
false
true
printf
Cependant, dans certains cas, une commande ne peut être que intégrée. L'un d'entre eux est cd
. Généralement, 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 de l’intégré et celui de l’exécutable peuvent différer (il s’agit en particulier de un problème pour echo
, qui a des comportements extrêmement 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 de définir des variables telles que POSIXLY_CORRECT
(même dans ce cas, il n'y a pas de garantie réelle).
Techniquement, rien ne vous empêche de fournir un système d’exploitation qui est aussi un shell et qui possède toutes les commandes intégrées. Près de cette extrémité extrême est le monolithique BusyBox . BusyBox est un simple binaire qui (en fonction du nom avec lequel il est appelé) peut se comporter comme n'importe quel sur 240 programmes , y compris un shell Almquist (ash
). Si vous désactivez PATH
lors de l'exécution de BusyBox ash
, les programmes disponibles dans BusyBox sont toujours accessibles sans spécifier PATH
. Ils s'approchent de ceux de Shell, à la différence que Shell lui-même est en quelque sorte intégré à BusyBox.
dash
)Si vous regardez la source dash
, le thread d'exécution ressemble à ceci (bien sûr, avec des fonctions supplémentaires impliquées lorsque des tubes ou d'autres choses sont utilisées):
main
→ cmdloop
→ evaltree
→ evalcommand
evalcommand
utilise ensuite findcommand
pour déterminer la nature de la commande. S'il s'agit d'une commande intégrée, then :
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 de fonction evalbltin
(selon que la commande intégrée est la commande eval
ou non) soit evalcmd
, ou le pointeur de cette fonction. Les fonctions réelles sont définies dans divers fichiers source. echo
, par exemple, 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 le numéro de ligne, ils peuvent donc changer sans préavis.
1 Les systèmes POSIX ont un cd
exécutable .
Note de côté:
Il y a beaucoup d'excellents articles sur Unix et Linux qui traitent du comportement de Shell. En particulier:
cd
?Si vous n'avez pas remarqué de tendance dans les questions répertoriées jusqu'à présent, elles impliquent presque toutes Stéphane Chazelas .
Vous ne pouvez pas trouver d’exécutable pour cd
car il n’en existe aucun.
cd
est une commande interne de votre shell (par exemple, bash
).
de man which
:
qui renvoie les noms de chemin des fichiers (ou liens) qui seraient exécutés dans l'environnement actuel si ses arguments avaient été fournis sous forme de commandes dans un shell strictement conforme à POSIX. Pour ce faire, il recherche dans le PATH les fichiers exécutables correspondant aux noms des arguments. Il ne suit pas de liens symboliques.
Comme nous pouvons le voir à la description de which
name__, il ne fait que vérifier PATH
name__. Donc, si vous avez implémenté bash function
, il ne vous montrera rien. Il est préférable d'utiliser la commande type
avec which
name __.
Par exemple, dans Ubuntu, ls
name__, commande alias ls --color=auto
.
$ type ls
ls is aliased to `ls --color=auto'
$ which ls
/bin/ls
Et si vous implémentez la fonction de test hello
name__:
$ function hello() { for i in {1,2,3}; do echo Hello $i;done }
$ which hello
which
ne montre rien. Mais type
name__:
$ type hello
hello is a function
hello ()
{
for i in {1,2,3};
do
echo Hello $i;
done
}
$ type cd
cd is a Shell builtin
Cela signifie que cd
est un construit dans le shell , il est dans bash
name__. Toutes les commandes intégrées à bash décrites dans man bash
, section Shell BUILTIN COMMANDS
Shell BUILTIN COMMANDS
Unless otherwise noted, each builtin command documented in this section
as accepting options preceded by - accepts -- to signify the end of the
options. The :, true, false, and test builtins do not accept options
and do not treat -- specially. The exit, logout, break, continue, let,
and shift builtins accept and process arguments beginning with - with‐
out requiring --. Other builtins that accept arguments but are not
specified as accepting options interpret arguments beginning with - as
invalid options and require -- to prevent this interpretation.