¿Por qué funciona "cd .." en la línea de comandos de Windows?

86

Al escribir cd..sin un espacio entre cdy ..el símbolo del sistema de Windows cambiará felizmente a la carpeta principal. ¿Hay alguna explicación para este comportamiento? El comando no sigue el formato estándar decommand<space>arguments

¿Funciona pero no debería?

Además, ¿por qué esto no crea resultados consistentes?

eco..

Jonas Köritz
fuente
24
La premisa de su pregunta parece estar rota. ¿Puede proporcionar alguna evidencia de su afirmación de que esto es sintácticamente incorrecto?
ligereza corre en órbita el
13
No creo que "argumentos de <espacio> de comando" haya sido el formato estándar en cmd (o cualquiera de sus predecesores); considere por ejemplo dir/ao la sintaxis VMS similar.
Grawity
66
El CD es muy especial. Puede escribir cd c:\program filessin comillas y aún funciona
phuclv
20
Aquí hay un artículo muy entretenido que explica las peculiaridades de la lógica de shell de Windows y qué caos puede causar: thedailywtf.com/articles/The-Core-Launcher
vsz
3
¿Por qué cd..funciona? Porque Microsoft pasó por la molestia de hacerlo explícitamente funcionar. cdes un comando integrado en el intérprete de comandos de Windows, y Microsoft puede hacer que su intérprete haga lo que quiera. (Como otro ejemplo, cdtampoco es necesario citar alrededor de directorios con espacios en el nombre.)
jamesdlin

Respuestas:

106

Como señalan algunas de las otras respuestas / comentarios, la idea de que debe haber un espacio después del comando no es correcta. Un ejemplo bien conocido es que puede escribir una barra diagonal después de un comando, sin necesidad de un espacio primero.

Sin embargo, hay otro comportamiento que es un poco menos comprendido y permite el " cd.." que está preguntando. Este comportamiento también permite que " cd\" funcione.

El comportamiento que describe es coherente para todos los comandos internos del intérprete de línea de comandos. Si tiene ciertos símbolos, incluido un punto, una barra diagonal o una barra diagonal inversa, los caracteres anteriores se verifican para ver si son un comando interno del shell "intérprete de línea de comandos" (CMD.EXE o su predecesor COMMAND.COM )

Esto se puede hacer antes de verificar si la palabra puede referirse a un archivo o subdirectorio. Eso es cierto para el cdcomando. Trágicamente, al hacer una muestra, descubrí que esto no sucede con el copycomando, por lo que los resultados son inconsistentes: no son necesariamente los mismos con todos los comandos internos. No continué mi búsqueda para comparar (mucho) otras líneas de comandos dely dir, por lo tanto, simplemente sugiero ser extremadamente cuidadoso si intentas confiar en lo que sucede sin un espacio.

Ahora, la pregunta también se hizo sobre el comando echo : esta es una excepción inusual, ya que creo que echo.es bastante conocida por los expertos de DOS. Esto probablemente fue documentado. El comportamiento, al menos en el CMD de Win7 , es que si el comando comienza con " echo.", se ignora el primer período. Entonces, " echo..hi" se convierte en salida de " .hi". La razón de esto es para que " echo." se pueda usar para imprimir una línea en blanco. En contraste, con Unix, puede hacer esto simplemente ejecutando el echocomando " " por sí mismo. Sin embargo, en DOS, ejecutar el echocomando " " por sí solo generará la configuración actual de " eco ". Del mismo modo, DOS trata " Echo *Off*" y "Echo *On*"como valores especiales que cambian la configuración de eco actual. Si realmente desea imprimir la palabra" Off", entonces" Echo.Off"hace el truco (al menos con versiones lo suficientemente recientes del intérprete de línea de comandos CMD de Microsoft ).

Entonces, al menos el echocomando tiene una explicación semi-razonable. En cuanto a los comandos restantes, solía pensar que los comandos internos tenían prioridad. Sin embargo, cuando intenté hacer algunas pruebas, descubrí que en realidad es bastante inconsistente. Lo demuestro a través de algunos ejemplos que documenté aquí.


Aquí hay unos ejemplos. Utilicé un símbolo del sistema elevado, para que UAC no se quejara de que escribiera en el directorio raíz. Esto se hizo con CMD.EXE de Microsoft Windows 7. Sospecho que los comportamientos pueden ser diferentes con otras versiones, como COMMAND.COM de versiones anteriores de MS-DOS, o software lanzado por otras compañías (COMMAND.COM de DR-DOS).

(Esta respuesta ya es bastante larga, por lo que no incluyo comandos para limpiar todo el desorden que hice en mi sistema de archivos. Hay un poco de limpieza, pero no mucho).

Aquí hay un ejemplo que prueba que el comando interno crea precedencia. (También demuestro la capacidad poco conocida de usar dos puntos dobles para ser un comentario efectivo, que también funciona bien en archivos por lotes. Técnicamente, en archivos por lotes, se procesa como una etiqueta que GOTO no puede alcanzar, y finaliza siendo más rápido que el comando REM.)

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

C: \ something> :: Eso se ejecutó desde el subdirectorio
C: \ something> cd \ a
C: \ a> :: Eso cambió mi directorio actual, por lo que el cd tuvo prioridad

Actualización: Tras una mayor experimentación, descubrí que el comando cd interno solo tiene prioridad sobre el sistema de archivos si el directorio especificado no incluye un punto. Entonces, si tiene un directorio llamado " a.bat ", puede ejecutar " **cd\a.bat**" y se ejecutará el archivo por lotes.

Esta exploración del comportamiento menos común (dado que la mayoría de los directorios probablemente no tienen puntos en ellos) me llevó a actualizar mis hallazgos. Resulta que el comando cd se está comportando más similar al comando copiar de lo que inicialmente pensé.

Aunque inicialmente pensé que los comandos cd y copy se comportaban de manera diferente, ahora descubrí que se debe al patrón de los nombres que estaba proporcionando. Aún así, revisé mis resultados anteriores y determiné que mis pruebas documentadas anteriores ayudan a mostrar algo de la diferencia entre lo que sucede cuando un nombre incluye un punto y una extensión, y cuándo no. Entonces, sigo incluyendo mis hallazgos anteriores a continuación (en su mayoría sin cambios, pero con algunas actualizaciones muy pequeñas, así que lo que digo es exacto).

Aquí hay un ejemplo que muestra que la copia , con una ruta completa, no usa la misma precedencia (favoreciendo el comando interno) que cd cuando no se usa ninguna extensión:

C: \ something> echo echo root >> \ try.bat
C: \ something> md copy
C: \ something> echo echo subdirectory >> copy \ try.bat
C: \ something> . \ Copy \ try.bat se ejecuta desde el subdirectorio
subdirectorio

C: \ algo> copiar \ try.bat
subdirectorio

C: \ algo> :: Huh? ¿Por qué no se anula y se ejecuta desde la raíz?
C: \ something> :: Aparentemente, el comando interno de copia no tenía prioridad sobre la verificación de un subdirectorio y nombre de archivo completo (aunque el comando interno de CD tenía prioridad, cuando el directorio no tenía extensión)
C: \ something> ::
C: \ algo>:: Otra prueba: puedo agregar períodos inútiles al final
C: \ something> . \ Copy .. \ try.bat
subdirectorio

C: \ something> :: Bien, genial. Pero esto no verificará el subdirectorio:
C: \ something> copy .. \ try.bat
        1 archivo (s) copiados.

C: \ something> :: Que ejecutó el comando interno de copia

Mis primeros hallazgos indicaron que estos resultados demuestran que la línea de comandos da prioridad:

  • al sistema de archivos (en lugar del comando de copia interno ) al especificar una barra diagonal inversa justo después del nombre del comando interno
  • al comando cd interno (en lugar del sistema de archivos) al especificar una barra diagonal inversa justo después del nombre del comando interno.
  • al comando de copia interno (en lugar del sistema de archivos) al especificar un punto justo después del nombre del comando interno.

Esto demuestra claramente que el comportamiento no es consistente entre el comando copiar (con un nombre de archivo completo que incluye una extensión) y el comando cd (sin una extensión como parte del nombre del directorio). Cuando se utiliza una barra diagonal inversa, el comando copiar (con la extensión completa del nombre de archivo) verificará primero el sistema de archivos, pero el comando cd no (si el directorio no contiene una extensión).

(Actualización: Al principio, pensé que la inconsistencia se basaba en un comportamiento diferente entre los programas. Más tarde, descubrí que la inconsistencia existía, pero se debió más a los parámetros proporcionados).

En realidad, incluso esas viñetas no son del todo precisas, aunque parece que demostré cada cosa individual que acabo de decir. El problema es que esa lista de viñetas no es lo suficientemente precisa como para ser completamente precisa. (Dejé las cosas imprecisas para que esas viñetas pudieran compararse con relativa facilidad y comprobarse con relativa facilidad).

Sin embargo, para ser más precisos, el primer punto de viñeta debe señalar que el shell de la línea de comando da prioridad:

  • al sistema de archivos (en lugar del comando de copia interno ) al especificar una barra diagonal inversa, y luego el resto de la ruta completa, justo después del nombre del comando interno

Lo siguiente demostrará por qué estoy haciendo esa distinción:

C: \ en otro lugar> echo Elevación UAC necesaria para esta línea >> \ needext
C: \ en otro lugar> echo Elevación UAC necesaria para esta línea >> \ needext.bat
C: \ en otro lugar> md. \ Copy C: \ en otro
lugar> echo @ Echo subdir >> copiar \ needext.bat
C: \ en otro lugar> . \ Copy \ needext
subdir

C: \ en otro lugar> copiar \ needext.bat
subdir

C: \ en otro lugar> copiar \ needext
        1 archivo (s) copiado.

C: \ anywhere> :: UAC también se necesita para las siguientes líneas
C: \ anywhere > del \ needext
C: \ anywhere > del \ needext.bat

(Tenga en cuenta que el último comando de copia buscó el archivo llamado \ needext , porque se usó el comando de copia interno . El archivo \ needext.bat solo se creó para ayudar a mostrar fácilmente que nunca fue utilizado por las líneas de comando que incluían la palabra copiar .)

En este punto, establecí algunas inconsistencias (con el comportamiento del comando copiar ) cuando se usa una barra invertida ...

A continuación, demostraré que hay cierta coherencia entre estos comandos. (Entonces, hay consistencia ... um ... a veces. Es posible que solo tengamos consistencia, de manera inconsistente.) Lo que mostraré a continuación es que el comando cd se comporta como el comando copiar cuando se usa un punto. El comando copiar usa el comando interno, y también el comando cd .

C: \ something> md. \ Yetmore

C: \ something> cd. \ Yetmore

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

C: \ something \ yetmore> md. \ test

C: \ something \ yetmore> md
. \ test Ya existe un subdirectorio o archivo. \ test.

C: \ something \ yetmore> :: Ese error muestra que ejecutamos el comando interno.
C: \ something \ yetmore> md .. \ test
C: \ something \ yetmore> md. \ Cd
C: \ something \ yetmore> copy. \ Md cd
. \ Md \ test.bat
        1 archivo copiado.

C: \ something \ yetmore> . \ Cd. \ Test
subdir

C: \ something \ yetmore> cd. \ Test
C: \ something \ yetmore \ test> :: el comando interno funcionó con un período
C: \ something \ yetmore \ test> cd ..
C: \ something \ yetmore> . \ cd .. \ test
subdir

C: \ something \ yetmore> cd .. \ test
C: \ something \ test> :: el comando interno también tuvo prioridad cuando dos períodos son usado

Entonces, durante la sesión de prueba inicial que se centró principalmente en los comandos cd y copy (con algún uso adicional de md y un poco de del ), la única vez que realmente teníamos prioridad en el sistema de archivos era con el comando copy , y luego el El sistema de archivos solo tenía prioridad cuando se usaba la ruta completa.

Después de una revisión posterior, descubrí que el comando cd también le daba prioridad al sistema de archivos cuando usaba una extensión. Al menos esto significa que los comandos internos están siendo tratados un poco más consistentes entre sí. Sin embargo, también significa que obtenemos un comportamiento diferente según los nombres de los objetos del sistema de archivos (los archivos o directorios). Parece que el comportamiento está utilizando una lógica interna muy, muy oscura. Por lo tanto, contar con este comportamiento para trabajar en diferentes sistemas operativos es algo que probablemente consideraría inseguro .

TOOGAM
fuente
"El comportamiento que usted describe es consistente para todos los comandos internos del intérprete de línea de comandos". ipconfigpor ejemplo funciona también.
Jonas Köritz
@ JonasKöritz: No. Puede poner una barra (hacia adelante) justo después del comando " IPConfig " y eso funcionará, por ejemplo IPCONFIG/ALL. Sin embargo, eso no es de lo que estaba hablando. " El comportamiento que usted describe " (en su pregunta) fue el comportamiento de colocar un punto justo después del nombre del comando. Si escribo IPConfig., recibo un error sobre un comando que no se encuentra. De manera similar (aunque esto no está relacionado con el comportamiento que estaba describiendo), si escribo IPCONFIG\ALL, puedo ejecutar un .\IPCONFIG\ALL.BATarchivo personalizado que hice. Por lo tanto /, no se tratan como .o `\`
TOOGAM
1
¡Aceptaré tu respuesta para apreciar el trabajo y la investigación que tomó para crearlo!
Jonas Köritz
2
@Calchas Prueba simple: intente ejecutar copy.exeo copy.comen cmd. No funciona, no es un ejecutable.
Luaan
1
@Luann: Respecto ipconfig, no estoy de acuerdo con tu conclusión. Esta pregunta es acerca de lo que está escrito al comienzo de una línea de comando. Windows / DOS identifica los ejecutables por extensión de nombre de archivo, por lo que no puede ejecutar un programa llamado "ipconfig" sin una extensión (en Windows, a diferencia de Unix que lo permite). Con respecto al siguiente comentario, no sé quién es "Calchas". (Cuando especifica un signo at, los siguientes son generalmente los primeros caracteres de un usuario que aparece en otra parte de la página). Estoy de acuerdo, al ejecutar " copy.exe" se usará el copycomando interno (y pasar .exe). (Puedes correr .\copy.exe)
TOOGAM
41

Asume que un nombre de comando y sus argumentos deben estar separados por un espacio, específicamente, pero esto no es cierto. Mientras la invocación se pueda interpretar sin ambigüedades, la invocación es válida.

En este caso, el primer argumento comienza con .y .no puede ser parte del nombre del comando, así cdy ..simplemente se analiza como dos fichas separadas.

Por lo general, su primer argumento comenzará con un carácter alfabético (por ejemplo, el comienzo de una ruta), por lo que "sangrará" en el nombre de su comando y causará un error ... pero eso no es un problema de sintaxis. Es semántico.

Puede ver el mismo efecto en el trabajo con otros comandos, que incluyen echo:

echo...
..

En este caso, obtenemos solo dos puntos porque el echocomando en sí tiene una regla especial , de modo que lo siguiente:

echo .

o, por extensión, esto:

echo.

genera solo una línea vacía. Es una conveniencia. Aparentemente se ha implementado ignorando un punto principal en el argumento.

Hola, esto es DOS / Batch. ¿Quieres cordura? :RE

Carreras de ligereza en órbita
fuente
2
Asumí esto porque es exclusivo de la línea de comandos de Windows, bash, por ejemplo, no te permitirá hacerlocd..
Jonas Köritz
47
@ JonasKöritz: Es un programa completamente diferente en un sistema operativo completamente diferente. Mi bicicleta tampoco lo permite cd..:)
Carreras de ligereza en órbita
15
@ JonasKöritz:alias cd..='cd ..'
mouviciel
55
@LightnessRacesinOrbit: Originalmente fue un atajo de filtrado .y ..que aparecen como directorios en cualquier otro directorio y, por lo que sé, nunca tuvo la intención de atrapar más que eso. De hecho, considero que la ocultación modelada como atributo de archivo es un diseño más limpio que tenerlo implícitamente del nombre del archivo.
Joey
44
@joey: creo que el punto más relevante no es que el enfoque de DOS era más simple, es que DOS no permitía los .nombres de archivo , lo que significaba que no podía ser parte del nombre de un comando, por lo tanto, debe haber sido parte del argumento . Incluso si DOS hubiera dividido el comando en argumentos como lo hacen los shells de Unix, aún colocaría un .comando después del comando en el primer argumento, porque no tendría sentido poner un carácter no válido en el nombre del comando.
Jules
19

El cd..comando es correcto y se definió así en el intérprete de comandos original command.comque más tarde se denominó cmd.exe.

El intérprete de comandos sabe cómo procesar cd.., porque .es un carácter especial, al igual que \.

Overmind
fuente
8
Supongo que el problema principal es que el comando no puede ser "sintácticamente incorrecto" porque la sintaxis no se especifica formalmente en ningún lado , por lo que si la implementación principal (cmd.exe y / o MS-DOS) lo acepta, entonces debe ser correcto.
Grawity
3
Además, CD no es un programa, sino un comando interno. Similar a Echo, que también es un comando interno, no necesita tener un espacio para que funcione. echo.funciona igual de bien, lo que imprimirá una línea vacía.
LPChip
2
@Overmind echoe tampoco funcionará, así que es lo mismo con cd, echo, md, etc.
LPChip
2
@ JonasKöritz, .no se descarta, solo se agrega un espacio. md.testy md .testambos crean el directorio .test. Escribiendo cd.testy cd .testcambiará al directorio .test.
daniel.neumann
66
@ JonasKöritz: Porque la sintaxis nunca ha sido argumentos de comando-espacio.
Carreras de ligereza en órbita
11

Es un truco de compatibilidad con versiones anteriores.

El intérprete de línea de comandos está diseñado para ser retrocompatible con los comandos del intérprete de comandos MSDOS original, que fue diseñado para ser retrocompatible con el intérprete de comandos CP / M. Ni CP / M ni MSDOS permitieron un .en un nombre de archivo (se interpretó como un separador entre dos partes del nombre de archivo, el nombre base y la extensión). Esto significaba que (al menos para las primeras versiones de DOS), el intérprete de comandos podría identificar eso si alcanzaba un '.' (o, de hecho, cualquier otro carácter que fuera ilegal en un nombre de archivo) pasó el final del nombre del comando y entró en los argumentos del comando. Esto se usaba con bastante frecuencia tanto en DOS como en CP / M; por ejemplo, dir/wera un comando muy común, equivalente al dir /wsignificado de listar archivos en formato horizontal.

Hoy en día, '.' puede aparecer en nombres de archivo. Esto causa algunas complicaciones en cómo analizar los comandos, pero el shell aún identifica un .que no es parte de un nombre de archivo exacto como el comienzo de los argumentos. Esto es necesario en gran medida porque millones de usuarios se han acostumbrado a escribir cd..o tienen un gran número de archivos por lotes que contienen ese echo.o cualquier otro número de comandos similares.

Jules
fuente