Pourquoi “cd ..” fonctionne-t-il dans la ligne de commande Windows?


86

Lorsque vous tapez cd..sans espace entre cdet ..l'invite de commande Windows basculera avec plaisir dans le dossier parent. Y a-t-il une explication à ce comportement? La commande ne suit pas le format standard decommand<space>arguments

Travailler mais ne devrait pas?

Aussi, pourquoi cela ne crée-t-il pas des résultats cohérents?

écho..


24
La prémisse de votre question semble être brisée. Pouvez-vous fournir des preuves à l'appui de votre affirmation selon laquelle cela est syntaxiquement incorrect?
Courses de légèreté en orbite

13
Je ne pense pas que "commande <espace> arguments" ait jamais été le format standard de cmd (ni aucun de ses prédécesseurs); considérons par exemple dir/aou la syntaxe VMS similaire.
Grawity

6
cd est très spécial. Vous pouvez taper cd c:\program filessans guillemets et cela fonctionne toujours
lundi

20
Voici un article très amusant qui explique les bizarreries de la logique du shell Windows et ce que cela peut causer: theedailywtf.com/articles/The-Core-Launcher
vsz Le

3
Pourquoi ça cd..marche? Parce que Microsoft a eu la peine de le faire fonctionner explicitement. cdest une commande intégrée à l'interpréteur de commandes de Windows et Microsoft peut obliger leur interpréteur à faire ce qu'il veut. (Autre exemple, cdil n'est pas nécessaire de citer les répertoires avec des espaces dans le nom.)
jamesdlin

Réponses:


106

Comme le notent certaines des autres réponses / commentaires, l’idée qu’il doit y avoir un espace après la commande n’est pas correcte. Un exemple bien connu est que vous pouvez taper une barre oblique après une commande sans avoir besoin d’espacer.

Cependant, il existe un autre comportement qui est un peu moins bien compris et permet le " cd.." que vous demandez. Ce comportement permet également que " cd\" fonctionne.

Le comportement que vous décrivez est cohérent pour toutes les commandes internes à l'interpréteur de ligne de commande. Si vous avez certains symboles, notamment un point, une barre oblique ou une barre oblique inverse, les caractères précédents sont vérifiés pour déterminer s’il s’agit d’une commande interne au shell "interpréteur de ligne de commande" (CMD.EXE ou son prédécesseur, COMMAND.COM). ).

Cela peut être fait avant de vérifier si le mot peut faire référence à un fichier ou à un sous-répertoire. Cela est vrai pour la cdcommande. Malheureusement, lors de la création d'un échantillon, j'ai constaté que cela ne se produisait pas avec la copycommande. Les résultats sont donc incohérents: ils ne sont pas nécessairement identiques pour toutes les commandes internes. Je n'ai pas poursuivi ma recherche pour comparer également (beaucoup) d'autres commandes delet dir, par conséquent, je suggère simplement d'être extrêmement prudent si vous essayez de vous fier à ce qui se passe sans espace.

Maintenant, la question a également été posée à propos de la commande echo : Il s’agit d’une exception inhabituelle dans la mesure où elle echo.est assez bien connue des experts de DOS. Cela a probablement été documenté. Le comportement, au moins dans le CMD de Win7 , est que si la commande commence par " echo.", la première période est ignorée. Ainsi, " echo..hi" se transforme en sortie de " .hi". La raison en est que " echo." peut être utilisé pour imprimer une ligne vierge. En revanche, avec Unix, vous pouvez le faire simplement en exécutant la echocommande " " seule. Toutefois, sous DOS, l’exécution de la echocommande " " seule produira le paramètre " echo " actuel . De même, DOS traite " Echo *Off*" et "Echo *On*"en tant que valeurs spéciales qui modifient le paramètre d'écho actuel. Si vous voulez réellement imprimer le mot" Off", alors" Echo.Off"fait l'affaire (au moins avec les versions assez récentes de l' interpréteur de ligne de commande CMD de Microsoft .)

Donc, au moins la echocommande a une explication semi-raisonnable. En ce qui concerne les commandes restantes, je pensais que les commandes internes étaient prioritaires. Cependant, quand j'ai essayé de faire des tests, j'ai trouvé que c'était plutôt incohérent. Je le démontre à travers quelques exemples que j'ai documentés ici.


Voici quelques exemples. J'ai utilisé une invite de commande avec privilèges élevés afin d'éviter que le contrôle de compte d'utilisateur m'écrive dans le répertoire racine. Cela a été fait avec CMD.EXE de Microsoft Windows 7. Je soupçonne que les comportements peuvent être différents avec d'autres versions, telles que COMMAND.COM à partir d'anciennes versions de MS-DOS ou des logiciels publiés par d'autres sociétés (COMMAND.COM de DR-DOS).

(Cette réponse est déjà assez longue, je n'inclus donc pas de commandes pour nettoyer tous les dégâts que j'ai causés sur mon système de fichiers. Il y a un petit peu de nettoyage, mais pas beaucoup.)

Voici un exemple qui prouve que la commande interne crée une priorité. (Je démontre également la capacité assez mal connue d’utiliser un double-point pour constituer un commentaire, ce qui fonctionne également dans les fichiers batch. Techniquement, dans les fichiers batch, il est traité comme une étiquette inaccessible par GOTO et se termine up étant plus rapide que la commande REM.)

C: \ quelque chose> md cd
C: \ quelque chose> echo echo subdir >> cd \ a.bat
C: \ quelque chose> md \ a
C: \ quelque chose> . \ Cd \ a.bat
subdir

C: \ quelque chose> :: Cela a fonctionné à partir du sous-répertoire
C: \ quelque chose> cd \ a
C: \ a> :: Cela a changé mon répertoire actuel, donc cd a priorité

Mise à jour: Lors d'expériences ultérieures, j'ai constaté que la commande cd interne n'avait priorité sur le système de fichiers que si le répertoire spécifié n'incluait pas de point. Donc, si vous avez un répertoire nommé " a.bat ", vous pouvez exécuter " **cd\a.bat**" et le fichier de commandes sera exécuté.

Cette exploration de comportements moins courants (puisque la plupart des annuaires ne contiennent probablement pas de points) m'a amené à mettre à jour mes résultats. Il se trouve que la commande cd se comporte en fait plus comme la commande copy que je le pensais initialement.

Bien que je pensais au départ que les commandes de copie et de CD se comportaient différemment, j’ai maintenant compris que c’était à cause du motif des noms que je fournissais. Néanmoins, j’ai passé en revue mes résultats antérieurs et déterminé que mes tests documentés antérieurs permettaient de montrer une partie de la différence entre ce qui se produit lorsqu’un nom comprend une période et une extension, et quand il n’en a pas. Donc, j'inclus toujours mes résultats les plus anciens ci-dessous (essentiellement inchangés, mais avec quelques mises à jour mineures, donc ce que je dis est exact).

Voici un exemple montrant qu'une copie , avec un chemin complet, n'utilise pas la même priorité (privilégiant la commande interne) que cd quand aucune extension n'est utilisée:

C: \ quelque chose> echo racine echo >> \ try.bat
C: \ quelque chose> copie md
C: \ quelque chose> echo echo sous-répertoire >> copie \ try.bat
C: \ quelque chose> . \ Copie \ try.bat est exécuté à partir le sous - répertoire
sous - répertoire

C: \ quelque chose> copier \ try.bat
sous - répertoire

C: \ quelque chose> :: Huh? Pourquoi cela n’a-t-il pas priorité et est-il parti de la racine?
C: \ quelque chose> :: Apparemment, la commande de copie interne n'était pas prioritaire sur la recherche d'un sous-répertoire et du nom de fichier complet (même si la commande cd interne était prioritaire, alors que le répertoire n'avait pas d'extension)
C: \ quelque chose> ::
C: \ quelque chose>:: Un autre test: je peux ajouter des points inutiles à la fin
C: \ quelque chose> . \ Copie .. \ try.bat
sous-répertoire

C: \ quelque chose> :: Ok, très bien. Mais alors cela ne vérifiera pas le sous-répertoire:
C: \ quelque chose> copier .. \ try.bat
        1 fichier (s) copié (s).

C: \ quelque chose> :: qui a exécuté la commande de copie interne

Mes premières découvertes indiquaient que ces résultats démontraient que le shell de ligne de commande donnait la priorité:

  • au système de fichiers (au lieu de la commande de copie interne ) lors de la spécification d'une barre oblique inverse juste après le nom de la commande interne
  • à la commande cd interne (au lieu du système de fichiers) lors de la spécification d’une barre oblique inverse juste après le nom de la commande interne.
  • à la commande de copie interne (au lieu du système de fichiers) lors de la spécification d'un point juste après le nom de la commande interne.

Cela montre clairement que le comportement n'est pas cohérent entre la commande copy (avec un nom de fichier complet, y compris une extension) et la commande cd (sans extension dans le nom du répertoire). Lors de l'utilisation d'une barre oblique inverse, la commande de copie (avec l'extension de nom de fichier complète) vérifie d'abord le système de fichiers, mais pas la commande cd (si le répertoire ne contient pas d'extension).

(Mise à jour: au début, je pensais que l'incohérence était basée sur un comportement différent entre les programmes. Plus tard, j'ai découvert que l'incohérence existait, mais était davantage causée par les paramètres fournis.)

En fait, même ces points ne sont pas tout à fait exacts, même si je semblais simplement démontrer chaque chose que je venais de dire. Le problème est que cette liste de points n’est pas assez précise pour être tout à fait exacte. (J'ai laissé des informations imprécises pour pouvoir comparer ces points et les vérifier assez facilement.)

Cependant, pour être plus précis, la première puce doit indiquer que le shell de ligne de commande donne la priorité:

  • pour le système de fichiers ( au lieu de l'intérieur copie commande) lors de la spécification d' une barre oblique inverse, et ensuite le reste du chemin complet, immédiatement après le nom de la commande interne

Ce qui suit va démontrer pourquoi je fais cette distinction:

C: \ ailleurs> écho élévation UAC nécessaire pour cette ligne >> \ needext
C: \ ailleurs> écho élévation UAC nécessaire pour cette ligne >> \ needext.bat
C: \ ailleurs> md. \ Copie
C: \ ailleurs> echo @ Echo subdir >> copier \ needext.bat
C: \ ailleurs> . \ Copy \ needext
sousdir

C: \ ailleurs> copier \ needext.bat
sousdir

C: \ ailleurs> copier \ needext
        1 fichier (s) copié (s).

C: \ ailleurs> :: UAC également nécessaire pour les lignes suivantes
C: \ ailleurs> del \ needext
C: \ ailleurs> del \ needext.bat

(Notez que la dernière commande de copie a recherché le fichier appelé \ needext , car la commande de copie interne a été utilisée. Le fichier \ needext.bat a été créé uniquement pour aider à montrer facilement qu'il n'a jamais été utilisé par les lignes de commande contenant le mot copy. .)

À ce stade, j’ai établi une certaine incohérence (avec le comportement de la commande copy ) lorsqu’une barre oblique inversée est utilisée ...

Ensuite, je démontrerai qu’il existe une certaine cohérence entre ces commandes. (Donc, il y a une cohérence ... euh ... parfois. Il se peut que nous n'ayons que de la cohérence, de manière incohérente.) Ce que je vais montrer maintenant, c'est que la commande cd se comporte plutôt comme la commande copy lorsque un point est utilisé. La commande copy utilise la commande interne, de même que la commande cd .

C: \ quelque chose> md. \ Yetmore

C: \ quelque chose> cd. \ Yetmore

C: \ quelque chose \ yetmore> md. \ Md
C: \ quelque chose \ yetmore> echo echo subdir >> md \ test.bat
C: \ yetmore> . \ md. \ test
subdir

C: \ quelque chose \ yetmore> md. \ test

C: \ quelque chose \ yetmore> md. \ test
Un sous-répertoire ou fichier. \ test existe déjà.

C: \ quelque chose \ yetmore> :: Cette erreur montre que nous avons exécuté la commande interne.
C: \ quelque chose \ encore plus> md .. \ test
C: \ quelque chose \ encore plus> md. \ Cd
C: \ quelque chose \ encore plus> copier. \ Md cd
. \ Md \ test.bat
        1 fichier (s) copié (s).

C: \ quelque chose \ yetmore> . \ Cd. \ Test
subdir

C: \ quelque chose \ yetmore> cd. \ Test
C: \ quelque chose \ yetmore \ test> :: la commande interne a fonctionné avec une période
C: \ quelque chose \ yetmore \ test> cd ..
C: \ quelque chose \ yetmore> . \ cd .. \ test
subdir

C: \ quelque chose \ yetmore> cd .. \ test
C: \ quelque chose \ test> :: commande interne a également priorité lorsque deux points sont utilisé

Ainsi, au cours de la session de test initiale qui a principalement porté sur les commandes cd et copy (avec quelques utilisations supplémentaires de md et un peu de del ), le seul moment où le système de fichiers a pris la priorité était avec la commande copy , puis Le système de fichiers n’était prioritaire que lorsque le chemin complet était utilisé.

Après un examen ultérieur, j’ai constaté que la commande cd donnait également la priorité au système de fichiers lors de l’utilisation d’une extension. Au moins, cela signifie que les commandes internes sont traitées un peu plus de cohérence entre elles. Cependant, cela signifie également que nous obtenons un comportement différent en fonction des noms des objets du système de fichiers (les fichiers ou les répertoires). Il semble que le comportement utilise une logique interne très obscure. Par conséquent, compter sur ce comportement pour fonctionner sur différents systèmes d’exploitation est probablement quelque chose de dangereux .


"Le comportement que vous décrivez est cohérent pour toutes les commandes internes à l'interpréteur de ligne de commande." ipconfigpar exemple fonctionne aussi.
Jonas Köritz

@ JonasKöritz: Non. Vous pouvez insérer une barre oblique juste après la commande " IPConfig " et cela fonctionnera, par exemple IPCONFIG/ALL. Cependant, ce n'est pas ce dont je parlais. " Le comportement que vous décrivez " (dans votre question) était le fait de placer un point juste après le nom de la commande. Si je tape, IPConfig.j'obtiens une erreur à propos d'une commande introuvable. De même (bien que cela ne soit pas lié au comportement que vous décriviez), si je tape, IPCONFIG\ALLje peux alors exécuter un .\IPCONFIG\ALL.BATfichier personnalisé que j'ai créé. Donc /, ne sont pas traités comme .ou `\`
TOOGAM

1
J'accepterai votre réponse pour apprécier le travail et les recherches qu'il a fallu pour le créer!
Jonas Köritz

2
@Calchas Simple test - essayez d'exécuter copy.exeou copy.comen cmd. Cela ne fonctionne pas - ce n'est pas un exécutable.
Luaan

1
@ Luann: En ce qui concerne ipconfig, je ne suis pas d'accord avec votre conclusion. Cette question concerne ce qui est tapé au début d'une ligne de commande. Windows / DOS identifie les exécutables par extension de nom de fichier, vous ne pouvez donc pas exécuter un programme appelé "ipconfig" sans extension (sous Windows, contrairement à Unix qui le permet). En ce qui concerne le commentaire suivant, je ne sais pas qui est "Calchas". (Lorsque vous spécifiez un signe arobase, voici les premiers caractères d'un utilisateur qui apparaissent ailleurs sur la page.) Je conviens que l'exécution de " copy.exe" utilisera la copycommande interne (et passera .exe). (Vous pouvez courir .\copy.exe)
TOOGAM

41

Vous supposez qu'un nom de commande et ses arguments doivent être séparés par un espace, en particulier, mais ce n'est pas vrai. Tant que l'invocation peut être interprétée sans ambiguïté, l'invocation est valide.

Dans ce cas, le premier argument commence par .et .ne peut pas faire partie du nom de la commande, donc cdet ..sont tout simplement analysé comme deux jetons séparés.

Habituellement, votre premier argument commence par un caractère alphabétique (par exemple, le début d'un chemin), ainsi, il "perdra" le nom de votre commande et provoquera une erreur ... mais ce n'est pas un problème de syntaxe. C'est une sémantique.

Vous pouvez voir le même effet au travail avec d'autres commandes, notamment echo:

echo...
..

Dans ce cas, nous n'obtenons que deux points car la echocommande elle-même a une règle spéciale , de sorte que:

echo .

ou, par extension, ceci:

echo.

affiche uniquement une ligne vide. C'est une commodité. Apparemment, cela a été mis en œuvre en ignorant une période de pointe dans l'argument.

Hé, c'est DOS / Batch. Vous voulez la santé mentale? :RÉ


2
J'ai supposé cela parce qu'il est unique en ligne de commande Windows, bash par exemple ne vous permettra pas de le fairecd..
Jonas Köritz

47
@ JonasKöritz: Il s'agit d'un programme complètement différent sur un système d'exploitation totalement différent. Mon vélo ne le permet pas non cd..plus :)
Courses de légèreté en orbite

15
@ JonasKöritz:alias cd..='cd ..'
mouviciel

5
@LightnessRacesinOrbit: A l' origine , il était un raccourci de filtrage .et ..qui apparaissent comme des répertoires dans tous les répertoires et autant que je sache , n'a jamais été destiné à attraper plus que cela. En fait, je considère la dissimulation modélisée comme un attribut de fichier comme une conception plus propre que si elle découle implicitement du nom de fichier.
Joey

4
@joey - Je pense que le point le plus pertinent n'est pas que l'approche DOS était plus simple, mais que DOS n'autorisait pas les .noms de fichiers , ce qui signifiait que cela ne pouvait pas faire partie d'un nom de commande et devait donc faire partie de l'argument . Même si DOS avait divisé la commande en arguments de la même manière que les shells Unix, il placerait toujours un .après la commande dans le premier argument, car cela n'aurait aucun sens de mettre un caractère non valide dans le nom de la commande.
Jules

19

La cd..commande est correcte et elle a été définie comme telle dans l'interpréteur de commande d'origine, command.comqui a ensuite été nommé cmd.exe.

L'interpréteur de commandes sait comment traiter cd..car il .s'agit d'un caractère spécial, tout comme \.


8
Je suppose que le problème principal est que la commande ne peut pas être "syntaxiquement incorrecte" car la syntaxe n'est spécifiée formellement nulle part . Par conséquent, si l'implémentation principale (cmd.exe et / ou MS-DOS) l'accepte, elle doit être correcte.
Grawity

3
De plus, CD n'est pas un programme, mais une commande interne. Semblable à Echo, qui est également une commande interne, il n’a pas besoin d’un espace pour fonctionner. echo.fonctionne tout aussi bien, ce qui imprimera une ligne vide.
LPChip

2
@ Overmind echoe ne fonctionnera pas non plus, donc c'est la même chose avec cd, echo, md, etc.
LPChip

2
@ JonasKöritz, le .n'est pas supprimé, mais seulement un espace est ajouté. md.testet md .testtous deux créent le répertoire .test. Tapez cd.testet cd .testva changer dans le répertoire .test.
daniel.neumann

6
@ JonasKöritz: Parce que la syntaxe n'a jamais été un argument d'espace de commande.
Courses de légèreté en orbite

11

C'est un hack de compatibilité ascendante.

L'interpréteur de ligne de commande est conçu pour être rétrocompatible avec les commandes de l'interpréteur de commandes MSDOS d'origine, qui a été conçu pour être rétrocompatible avec l'interpréteur de commandes CP / M. Ni CP / M ni MSDOS n'autorisaient un .dans un nom de fichier (celui-ci était interprété comme un séparateur entre deux parties du nom de fichier, le nom de base et l'extension). Cela signifiait que (du moins pour les premières versions de DOS), l'interpréteur de commande pourrait l'identifier s'il atteignait un '.' (ou bien tout autre caractère qui était illégal dans un nom de fichier), il passait la fin du nom de la commande et figurait dans les arguments de la commande. C’était assez courant sous DOS et CP / M. Par exemple, il dir/ws’agissait d’une commande très courante, équivalente à la dir /wsignification de la liste des fichiers au format horizontal.

Aujourd'hui, '.' peut apparaître dans les noms de fichiers. Cela entraîne certaines complications lors de l'analyse des commandes, mais le shell identifie toujours un .début ne faisant pas partie d'un nom de fichier exact comme étant le début des arguments. Cela est principalement dû au fait que des millions d’utilisateurs se sont habitués à taper cd..ou possèdent un grand nombre de fichiers de commandes contenant cette commande echo.ou un nombre quelconque de commandes similaires.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.