87 votes

Pourquoi "cd " fonctionne-t-il dans la ligne de commande de Windows ?

Lorsque vous tapez cd.. sans espace entre les deux cd y .. l'invite de commande de Windows passe volontiers au dossier parent. Y a-t-il une explication à ce comportement ? La commande ne respecte pas le format standard de command<space>arguments

Working but shouldn't?

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

echo..

107voto

frooyo Points 658

Comme l'indiquent certaines des autres réponses/commentaires, l'idée selon laquelle 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'un espace au préalable.

Cependant, il existe un autre comportement, un peu moins connu, qui permet au " cd.. " que vous demandez. Ce comportement permet également de " cd\ " pour travailler.

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, alors les caractères précédents sont vérifiés pour voir s'il s'agit d'une commande interne à l'"interpréteur de ligne de commande" Shell (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 le cd commande. Tragiquement, en réalisant un échantillon, j'ai constaté que cela ne se produit pas avec la commande copy les résultats sont donc incohérents : ils ne sont pas nécessairement les mêmes avec toutes les commandes internes. Je n'ai pas continué ma recherche pour comparer aussi (beaucoup) d'autres lignes de commandes del y dir Je vous suggère donc simplement d'être extrêmement prudent si vous essayez de vous fier à ce qui se passe sans espace.

Maintenant, la question portait aussi sur le echo commande : C'est une exception inhabituelle, dans la mesure où je pense que echo. est assez bien connu des experts du DOS. Cela a probablement été documenté. Le comportement, au moins dans la version de Win7 CMD est que si la commande commence par " echo. ", alors le premier point est ignoré. Ainsi, " echo..hi " se transforme en une sortie de " .hi ". La raison en est que " echo. "peut être utilisé pour imprimer une ligne blanche. En revanche, sous Unix, vous pouvez faire cela simplement en exécutant la commande " echo "par elle-même. Cependant, sous DOS, l'exécution de la commande " echo "Par elle-même, la commande " echo ". De même, DOS traite " Echo *Off* " et " Echo *On* "comme des valeurs spéciales qui modifient le paramètre actuel de l'écho. Si vous voulez réellement imprimer le mot " Off ", puis " Echo.Off "fait l'affaire (du moins avec les versions assez récentes de l'éditeur de logiciels Microsoft CMD interpréteur de ligne de commande).

Donc, au moins le echo a une explication semi-raisonnable. Quant aux autres commandes, j'avais l'habitude de penser que les commandes internes avaient la priorité. Cependant, lorsque j'ai essayé de faire quelques tests, j'ai constaté que c'était en fait 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 élevée, afin que l'UAC ne se plaint pas que j'écrive dans le répertoire racine. Ceci a été fait avec le CMD.EXE de Microsoft Windows 7. Je pense que les comportements peuvent être différents avec d'autres versions, comme COMMAND.COM des 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, donc je n'inclus pas les commandes pour nettoyer tout le désordre que j'ai fait sur mon système de fichiers. Il y a un tout petit peu de nettoyage, mais pas beaucoup).

Voici un exemple qui prouve que la commande interne crée la préséance. (Je démontre également la possibilité peu 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 qui ne peut pas être atteinte par GOTO, et finit par être plus rapide que la commande REM).

C:\something > md cd
C:\something > echo echo sous-répertoire >> cd \a.bat
C:\something > md \a
C:\something > . \cd\a.bat
sous-répertoire

C:\something > : : That ran from the subdir
C:\something > cd \a
C:\a > : : Cela a changé mon répertoire courant, donc cd a prévalu

Mise à jour : Après d'autres expériences, j'ai découvert que l'interne cd ne prend le pas sur le système de fichiers que si le répertoire spécifié ne comporte pas de point. Ainsi, si vous avez un répertoire nommé " a.b ", alors vous pouvez exécuter " **cd\a.bat** "et le fichier batch sera exécuté.

Cette exploration d'un comportement moins courant (puisque la plupart des annuaires ne comportent probablement pas de points) m'a conduit à mettre à jour mes conclusions. Il s'avère que le cd se comporte en fait de manière plus similaire à la commande copie que je ne le pensais au départ.

Bien que j'ai d'abord pensé que le cd y copie se comportaient différemment, j'ai maintenant compris que c'était à cause du modèle des noms que je fournissais. J'ai tout de même revu mes résultats précédents, et déterminé que mes tests documentés aident à montrer une partie de la différence entre ce qui se passe lorsqu'un nom inclut un point et une extension, et lorsqu'il n'en inclut pas. Je continue donc à inclure mes anciens résultats ci-dessous (en grande partie inchangés, mais avec quelques mises à jour très mineures pour que ce que je dis soit exact).

Voici un exemple de démonstration copie avec un chemin complet, n'utilise pas la même préséance (favorisant la commande interne) que la commande cd lorsqu'aucune extension n'est utilisée :

C:\something > echo echo root >> \try.bat
C:\something > copie md
C:\something > écho du sous-répertoire >> copie \try.bat
C:\something > . \copy\try.bat s'exécute à partir du sous-répertoire
sous-répertoire

C:\something > copie \try.bat
sous-répertoire

C:\something > : : Huh ? Pourquoi ça n'a pas été remplacé et exécuté par root ?
C:\something > : : Apparemment, l'interne copie n'avait pas la priorité sur la vérification d'un sous-répertoire et d'un nom de fichier complet (même si la commande interne cd était prioritaire, lorsque le répertoire n'avait pas d'extension).
C:\something > : :
C:\something > : : Un autre test : Je peux ajouter des points inutiles à la fin
C:\something > . \copy..\try.bat
sous-répertoire

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

C:\something > ::Cela a lancé la commande de copie interne

Selon mes premières constatations, ces résultats démontrent que la ligne de commande Shell est prioritaire :

  • vers le système de fichiers (au lieu de la fonction interne copie ) en spécifiant une barre oblique inverse juste après le nom de la commande interne
  • à l'interne cd (au lieu du système de fichiers) en spécifiant une barre oblique inverse juste après le nom de la commande interne.
  • à l'interne copie (au lieu du système de fichiers) en spécifiant un point juste après le nom de la commande interne.

Cela démontre clairement que le comportement n'est pas cohérent entre le copie (avec un nom de fichier complet incluant une extension) et la commande cd (sans extension dans le nom du répertoire). Lorsqu'on utilise une barre oblique inverse, la commande copie (avec l'extension complète du nom de fichier) vérifiera d'abord le système de fichiers, mais la commande cd ne le fera pas (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 bel et bien, mais qu'elle é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 viens de démontrer chaque chose que je viens de dire. Le problème est que cette liste de points n'est pas assez précise pour être complètement exacte. (J'ai laissé les choses imprécises pour que ces puces puissent être comparées relativement facilement, et vérifiées relativement facilement).

Toutefois, pour être plus précis, le premier point devrait indiquer que la ligne de commande Shell est prioritaire :

  • vers le système de fichiers (au lieu de la fonction interne copie ) en spécifiant un backslash, et puis le reste du chemin complet, juste après le nom de la commande interne

Les paragraphes suivants montrent pourquoi je fais cette distinction :

C:\elsewhere > echo Élévation de l'UAC nécessaire pour cette ligne >> \needext
C:\elsewhere > echo Élévation de l'UAC nécessaire pour cette ligne >> \needext.bat
C:\elsewhere > md. \copy
C:\elsewhere > echo @Echo sous-répertoire >> copie \needext.bat
C:\elsewhere > . \copy\needext
sous-répertoire

C:\elsewhere > copie \needext.bat
sous-répertoire

C:\elsewhere > copie \needext
        1 fichier(s) copié(s).

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

(Notez que le dernier copie La commande a recherché le fichier appelé \needext car l'interne copie 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 qui comprenaient le mot copie .)

À ce stade, j'ai établi une certaine incohérence (avec le comportement de la copie ) lorsqu'un backslash est utilisé...

Ensuite, je vais démontrer qu'il existe une certaine cohérence entre ces commandes. (Donc, il y a cohérence... hum... parfois. Nous pourrions n'avoir de la cohérence que de manière incohérente). Ce que je vais montrer ensuite, c'est que la cd se comporte un peu comme la commande copie lorsqu'un point est utilisé. Le site copie utilise la commande interne, de même que la commande cd commandement.

C:\something > md. \yetmore

C:\something > cd. \yetmore

C:\something\yetmore > md. \md
C:\something\yetmore > echo echo sous-répertoire >> md \test.bat
C:\something\yetmore > . \md.\test
sous-répertoire

C:\something\yetmore > md. \test

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

C:\something\yetmore > : : Cette erreur montre que nous avons exécuté la commande interne.
C:\something\yetmore > md.. \test
C:\something\yetmore > md. \cd
C:\something\yetmore > copie. \md cd
. \md\test.bat
        1 fichier(s) copié(s).

C:\something\yetmore > . \cd.\test
sous-répertoire

C:\something\yetmore > cd. \test
C:\something\yetmore\test > ::la commande interne a fonctionné avec une période
C:\something\yetmore\test > cd..
C:\something\yetmore > . \cd..\test
sous-répertoire

C:\something\yetmore > cd.. \test
C:\something\test > : : la commande interne est également prioritaire lorsque deux périodes sont utilisées

Ainsi, au cours de la session de test initiale qui s'est principalement concentrée sur le cd y copie (avec quelques utilisations supplémentaires de md et un peu de del ), la seule fois où le système de fichiers est vraiment prioritaire, c'est avec la fonction copie et le système de fichiers ne prenait la priorité qu'en utilisant le chemin complet.

Après un examen ultérieur, j'ai constaté que le cd donne é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 de manière un peu plus cohérente les unes avec les autres. 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). Cela semble indiquer que le comportement utilise une logique interne vraiment, vraiment obscure. Par conséquent, compter sur ce comportement pour fonctionner sur différents systèmes d'exploitation est quelque chose que je considérerais probablement comme étant non sécurisé à faire.

41voto

user64178 Points 11

Vous supposez que le nom d'une commande et ses arguments doivent être séparés par un espace, précisément, 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 . y . ne peut pas faire partie du nom de la commande, donc cd y .. sont simplement analysés comme deux jetons distincts.

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

Vous pouvez voir le même effet à l'œuvre avec d'autres commandes, dont les suivantes echo :

echo...
..

Dans ce cas, nous n'obtenons que deux périodes car le site echo La commande elle-même a une règle spéciale de sorte que l'on puisse dire ce qui suit :

echo .

ou, par extension, ceci :

echo.

ne sort qu'une ligne vide. C'est une commodité. Apparemment, il a été implémenté en ignorant un point de tête dans l'argument.

Hé, c'est DOS/Batch. Tu veux du bon sens ? :D

18voto

Overmind Points 9514

があります。 cd.. est correcte et elle était définie comme cela dans l'interpréteur de commandes original command.com qui a ensuite été nommé cmd.exe .

L'interpréteur de commandes sait comment traiter cd.. parce que . est un caractère spécial, tout comme \ .

11voto

Jules Points 421

C'est un hack de rétrocompatibilité.

L'interpréteur de ligne de commande est conçu pour être rétrocompatible avec les commandes de l'interpréteur de commande MSDOS original, qui était conçu pour être rétrocompatible avec l'interpréteur de commande CP/M. Ni CP/M ni MSDOS n'autorisaient une commande de type . dans un nom de fichier (il était interprété comme un séparateur entre deux parties du nom de fichier, le nom de base et l'extension). Cela signifie que (au moins pour les premières versions du DOS), l'interpréteur de commande pouvait identifier que s'il atteignait un '.' (ou tout autre caractère illégal dans un nom de fichier), il dépassait la fin du nom de la commande et se trouvait dans les arguments de la commande. Ceci était assez couramment utilisé à la fois dans DOS et CP/M -- par exemple, dir/w était une commande très courante, équivalente à dir /w c'est-à-dire pour lister les fichiers dans un format horizontal.

De nos jours, '.' peut apparaître dans les noms de fichiers. Cela entraîne quelques complications dans la façon d'analyser les commandes, mais le Shell toujours identifie un . qui ne fait pas partie d'un nom de fichier exact comme étant le début des arguments. Ceci est nécessaire en grande partie parce que des millions d'utilisateurs ont pris l'habitude de taper cd.. ou avoir un grand nombre de fichiers batch contenant cette ou echo. ou toute autre commande similaire.

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X