Pourquoi cd n'est pas un programme?

129

Je me suis toujours demandé pourquoi ce cdn'était pas un programme, mais je n'ai jamais réussi à trouver la réponse.

Quelqu'un sait pourquoi c'est le cas?

AkshaiShah
la source
1
Je me souviens avoir lu (je ne trouve pas où) que la cdcommande unix originale était un programme séparé. La coque traitée spécialement en ce qu'elle n'a pas fork, juste exec. Et quand ce cdserait fini, ça serait exec sh. Je ne sais pas si c'est une histoire vraie.
camh
Quel serait le but? Si cela ajoute une manipulation spéciale, appelez simplement le chdirsyscall. sources: v1 v5 v7 (première version avec Bourne Shell)
Mikel
2
@camh, c'est une histoire vraie. J'ai également lu cela dans un article de Dennis M. Ritchie intitulé «L'évolution du système de partage du temps Unix», Revue technique 63 des laboratoires AT & T Bell, 6 (6), deuxième partie, octobre 1984.
jlliagre
@ Mikel: Je conviens que cela semble inutile, mais je ne faisais que relater une histoire à cdce sujet que j'avais lue. J'avais clairement tort à propos de l'aspect, maintenant que @jlliagre a rempli les détails.
camh

Réponses:

172

La cdcommande modifie le "répertoire de travail en cours", non?

"Répertoire de travail en cours" est une propriété unique pour chaque processus.

Donc, si cdc'était un programme ça marcherait comme ça:

  1. cd foo
  2. le cdprocessus commence
  3. le cdprocessus change le répertoire pour le processus cd
  4. le cdprocessus se termine
  5. votre shell a toujours le même état, y compris le répertoire de travail en cours, avant le démarrage.
Daniel Pittman
la source
8
Vos cinq étapes sont correctes mais "s'il cds'agissait d'un programme, il fonctionnerait comme ceci" devrait être "lorsqu'il cdest utilisé dans sa mise en œuvre de programme externe, cela fonctionne comme cela".
Juillet
1
N'étant pas un programmeur système, ni vraiment une connaissance approfondie des interactions avec le shell, je m'attendais à ce que le shell expose son répertoire de travail actuel et que cd soit un programme qui accède à cette propriété et la modifie. Après avoir examiné cette réponse, il est clair que comprendre que cela fonctionne probablement de manière sous-optimale pour de nombreuses raisons.
Jason
108

cdEn plus d'être un shell intégré, c'est aussi un programme sur les systèmes d'exploitation compatibles POSIX. Ils doivent fournir des exécutables indépendants pour les utilitaires habituels, tels que cd. Ceci est par exemple le cas avec Solaris , AIX , HP-UX et OS X .

De toute évidence, une commande intégrée cdest toujours obligatoire car son implémentation externe ne modifie pas le répertoire shell en cours. Cependant, ce dernier peut toujours être utile. Voici un exemple montrant comment POSIX envisage l'utilisation de cette cdcommande:

find . -type d -exec cd {} \;

Sur un système POSIX, cet oneliner signalera un message d'erreur pour tous les répertoires non autorisés cd. Sur la plupart des distributions Gnu / Linux, le message d'erreur suivant s'affiche:

find: `cd': No such file or directory

Et voici la réponse à votre question, " Pourquoi le CD n'est-il pas un programme? " De l'un des co-auteurs Unix d'origine. Sur une version très tôt Unix, cd(orthographié chdirà cette époque) était un programme externe. Il a simplement cessé de fonctionner de manière inattendue après forksa première mise en œuvre.

Citant Dennis Ritchie :

Au beau milieu de notre jubilation, il a été découvert que la commande chdir (changer le répertoire en cours) avait cessé de fonctionner. Il y avait beaucoup de lecture de code et d'introspection anxieuse sur la manière dont l'ajout de fork aurait pu rompre l'appel de chdir. Finalement, la vérité se fit jour: dans l'ancien système, chdir était un ordre ordinaire; il a ajusté le répertoire en cours du processus (unique) associé au terminal. Sous le nouveau système, la commande chdir a correctement modifié le répertoire en cours du processus créé pour l'exécuter, mais ce processus s'est rapidement terminé et n'a eu aucun effet sur son shell parent! Il était nécessaire de faire de chdir une commande spéciale, exécutée en interne dans le shell. Il se trouve que plusieurs fonctions analogues à des commandes ont la même propriété, par exemple login.

Source: Dennis M. Ritchie, « L’évolution du système de partage du temps Unix », Revue technique des laboratoires AT & T Bell 63 (6), Partie 2, octobre 1984, p. 1577–93.

Unix Version 1 (Mars 1971) La page de manuel chdir indique:

Comme un nouveau processus est créé pour exécuter chaque commande, chdir serait inefficace s’il était écrit en tant que commande normale. Il est donc reconnu et exécuté par Shell.

jlliagre
la source
10
... donc, apparemment, POSIX demande qu’il y ait un cdexécutable indépendant , mais qu’il ne fasse rien (sauf éventuellement émettre des messages d’erreur s’il est appelé avec de mauvais arguments). Bizarre.
Ilmari Karonen
4
Eh bien, si c'est vrai, ce ne serait pas la chose la plus stupide de POSIX.
Kaz
5
La page POSIX cd indique également que "cd ayant une incidence sur l’environnement d’exécution du shell actuel, il est toujours fourni comme un shell intégré dans le shell.".
Mikel
6
@Kaz, ce ne sont pas des choses complètement différentes. Ils font la même chose mais seule la commande intégrée affecte le shell actuel.
Jlliagre
13
@ Kaz: S'il vous plaît, ne m'appelez pas stupide tant que je ne fais que rapporter un fait. Vous pouvez être d'accord ou non avec POSIX mais ne tirez pas sur le messager.
Jlliagre
47

De l'introduction Bash ( Qu'est-ce qu'un shell? ):

Les shells fournissent également un petit ensemble de commandes intégrées implémentant des fonctionnalités impossibles ou peu pratiques à obtenir via des utilitaires distincts. Par exemple, cd, break, continueet exec) ne peuvent pas être mis en œuvre en dehors de la coquille , car ils manipulent directement la coquille elle - même. Le history, getopts, kill, ou pwdbuiltins, entre autres, pourraient être mises en œuvre dans les services publics distincts, mais ils sont plus faciles à utiliser comme les commandes internes. Toutes les fonctions intégrées du shell sont décrites dans les sections suivantes.

cjc
la source
29

Pour April Fool, cette année, j’ai écrit une version autonome decd .

Personne n'a la blague. Soupir.

Quiconque n’est pas sûr que cela cddoit être intégré au shell devrait le télécharger, le construire et l’essayer.

Lisez aussi sa page de manuel. :)

Warren Young
la source
Code vraiment utile! :-)
dschulz
6
C'est bien de voir quelqu'un qui travaille pour rendre Gnu / Linux plus compatible POSIX. Votre implémentation n’est pas seulement une bonne blague, mais il manque en fait quelque chose aux distributions Linux ...
mercredi
8
Je pense que je vais essayer encore l'année prochaine, citant le problème POSIX. ;)
Warren Young
6 ans plus tard: Et toi?
Peter A. Schneider
@ PeterA.Schneider: Je pensais qu'il était clair que je plaisantais, alors pour être clair, non, je ne vais pas vraiment faire beaucoup d'efforts pour essayer d'intégrer cela dans des systèmes d'exploitation et des projets similaires à COS tels que Cygwin, qui actuellement manque /bin/cd. Si vous voulez prendre mon code et en faire votre propre quête personnelle, vous pouvez le faire.
Warren Young
4

La cdcommande en shell ne peut pas être un processus séparé car sous Unix, il n’existe aucun mécanisme permettant de modifier le répertoire de travail actuel d’un processus différent (pas même le processus parent).

S'il cds'agissait d'un processus différent, il devrait alors modifier le répertoire de travail actuel de son parent (shell), ce qui n'est pas possible sous Unix. Au lieu de cela cdest une commande intégrée spéciale. Les appels de shell fonctionnent comme chdir()et fchdir() changent son propre répertoire de travail actuel.

Remarque: le noyau stocke le numéro d'inode du répertoire de travail actuel pour chaque processus. Le processus enfant hérite cwdde son parent.

saurav1405
la source
0

cd est une commande intégrée du shell. Aussi facile que ça. L'homme cd dit tout. la commande cd modifie le répertoire de travail de tous les interprètes et (dans un environnement threadé) de tous les threads.


la source
Parce que le shell est l'environnement qui prend en charge vos répertoires de travail actuels ($ PDW ...) ou cdable_vars. Cette fonction intégrée est finalement la façon dont toutes les commandes visibles par l'utilisateur doivent modifier le répertoire de travail actuel. Vous pouvez le tester de cette façon: compilez le bash sans cd.c et essayez d’écrire votre propre script cd, qui essaie de prendre en charge tous les environnements cdable_vars. Cette question est aussi plus un développeur lié. Je parie qu'ils pourraient vous répondre plus en détail à cette question.
2
Il y a une très bonne raison technique cdintégrée. Je vous suggérerais de lire les réponses les mieux classées et de réfléchir à la manière d'améliorer votre réponse.
Thorbjørn Ravn Andersen
La réponse la mieux classée est la pire que j'ai jamais lue! Mais hein? Qui suis je!
3
Mais cela répond à la question pourquoi .
Thorbjørn Ravn Andersen
-1

Je pense qu’une chose qui manque à la réponse des gens est que le répertoire courant est une variable d’environnement que chaque programme peut changer. Si vous utilisez la commande 'export' pour voir la liste de vos variables d'environnement actuelles, vous aurez:

declare -x PWD="/home/erfan"

dans vos résultats. Ainsi, par la commande 'cd', nous voulons simplement modifier cette variable interne. Je pense que si nous essayons, nous pouvons modifier la variable PWD de n’importe quel pty en shell, bien sûr. Comme:

cder    #change current PTY $PWD variable

Mais je pense qu’il n’est pas nécessaire dans les cas normaux. En un autre mot, nous prenons l’aide de bash (ou n’importe quel shell) pour modifier sa variable interne définie.

Erfankam
la source
3
Bien qu'il soit vrai que les shells Bourne exposent le répertoire de travail actuel sous la forme $ PWD, ce n'est pas l'emplacement de stockage principal; l'emplacement réel se trouve dans la structure par processus du noyau. Il est donc incorrect de dire que le CWD "est une variable d'environnement". Si cela a fonctionné comme vous le suggérez, ce C-liner deux imprimerait le ..chemin, pas le chemin que vous avez commencé à partir de : #include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }(C shells exposent l'encéphalopathie des cervidés en% au lieu CWD, en passant.)
Warren Jeune
Permet d'ajouter quelques lignes à votre application. #include <stdlib.h> int main (void) {chdir (".."); put (getenv ("PWD")); setenv (P "PWD", "/", 1); put (getenv ("PWD")); } Qu'aurons-nous comme résultats?
Erfankam
3
Cela écrasera simplement la valeur d'une variable, sans aucun effet secondaire sur le CWD. Ceci est un meilleur test pour montrer que: #include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }Il montrera le répertoire à partir duquel vous avez commencé le programme, pas /.
Warren Young
Je pense que chaque processus a aussi un répertoire de travail et une variable de chemin. Ainsi, vous changez simplement cet attribut de processus par chdir. Shell a aussi cet attribut et par cd nous modifions cet attribut.
Erfankam
4
Non, je vous dis que cela $PWDn'a de sens que pour le shell Bourne. C'est juste un moyen pour le shell de communiquer quelque chose qu'il sait à ses scripts afin qu'ils n'aient pas à appeler pwdpour le trouver. Tout programme autonome dépendant de la valeur de $PWDsera peu fiable.
Warren Young