Por que “cd ..” funciona na linha de comando do Windows?

86

Ao digitar cd..sem um espaço entre cde ..prompt de comando do Windows irá alegremente mudar para a pasta pai. Existe uma explicação para esse comportamento? O comando não segue o formato padrão decommand<space>arguments

Trabalhando, mas não deveria?

Além disso, por que isso não cria resultados consistentes?

eco..

Jonas Köritz
fonte
24
A premissa da sua pergunta parece estar quebrada. Você pode fornecer alguma evidência para sua alegação de que isso está sintaticamente incorreto?
Corridas do Lightness em órbita
13
Eu não acho que "command <space> argumentos" já tenha sido o formato padrão no cmd (ou em qualquer um de seus predecessores); considere, por exemplo, dir/aou a sintaxe semelhante do VMS.
grawity
6
CD é muito especial. Você pode digitar cd c:\program filessem aspas e ainda funciona
phuclv
20
Aqui está um artigo muito interessante que explica as peculiaridades da lógica shell do Windows, e que caos pode causar: thedailywtf.com/articles/The-Core-Launcher
vsz
3
Por que cd..funciona? Porque a Microsoft enfrentou o problema de explicitamente fazê-lo funcionar. cdé um comando incorporado ao interpretador de comandos do Windows e a Microsoft pode fazer com que o intérprete faça o que quiser. (Como outro exemplo, cdtambém não precisa citar torno de diretórios com espaços no nome.)
jamesdlin

Respostas:

106

Como algumas das outras respostas / comentários observam, a idéia de que deve haver um espaço após o comando não está correta. Um exemplo conhecido é que você pode digitar uma barra após um comando, sem precisar primeiro de um espaço.

No entanto, existe outro comportamento que é um pouco menos compreendido e permite o " cd.." que você está perguntando. Esse comportamento também permite que " cd\" funcione.

O comportamento que você descreve é ​​consistente para todos os comandos internos ao interpretador de linha de comando. Se você tiver determinados símbolos, incluindo um ponto final, barra invertida ou barra invertida, os caracteres anteriores serão verificados para ver se são um comando interno ao shell "interpretador de linha de comando" (CMD.EXE ou seu predecessor, COMMAND.COM )

Isso pode ser feito antes de verificar se a palavra pode se referir a um arquivo ou subdiretório. Isso é verdade para o cdcomando. Tragicamente, ao fazer uma amostra, descobri que isso não acontece com o copycomando, portanto os resultados são inconsistentes: eles não são necessariamente os mesmos com todos os comandos internos. Eu não continuei minha pesquisa para comparar (muito) outras linhas de comando dele dir, por isso, sugiro ser extremamente cuidadoso se você tentar confiar no que acontece sem um espaço.

Agora, a pergunta também foi feita sobre o comando echo : Esta é uma exceção incomum, pois acho que echo.é bastante conhecida pelos especialistas do DOS. Provavelmente isso foi documentado. O comportamento, pelo menos no CMD do Win7 , é que, se o comando iniciar com " echo.", o primeiro período será ignorado. Então, " echo..hi" se transforma na saída de " .hi". A razão para isso é " echo." que pode ser usada para imprimir uma linha em branco. Por outro lado, com o Unix, você pode fazer isso simplesmente executando o " echo" comando por si só. No entanto, no DOS, executar o echocomando " " por si só produzirá a configuração " eco " atual . Da mesma forma, o DOS trata " Echo *Off*" e "Echo *On*"como valores especiais que alteram a configuração de eco atual. Se você realmente deseja imprimir a palavra" Off", então" Echo.Off"faz o truque (pelo menos com versões suficientemente recentes do interpretador de linha de comando CMD da Microsoft .)

Portanto, pelo menos o echocomando tem uma explicação semi-razoável. Quanto aos comandos restantes, eu costumava pensar que os comandos internos tinham prioridade. No entanto, quando tentei fazer alguns testes, descobri que isso é realmente inconsistente. Demonstro isso através de alguns exemplos que documentamos aqui.


Aqui estão alguns exemplos. Eu usei um prompt de comando elevado, para que o UAC não se queixasse de mim escrevendo no diretório raiz. Isso foi feito com o CMD.EXE do Microsoft Windows 7. Suspeito que os comportamentos possam ser diferentes com outras versões, como o COMMAND.COM de versões anteriores do MS-DOS ou com o software lançado por outras empresas (COMMAND.COM do DR-DOS).

(Essa resposta já é bastante longa, então não incluo comandos para limpar toda a bagunça que fiz no meu sistema de arquivos. Há um pouquinho de limpeza, mas não muita.)

Aqui está um exemplo que prova que o comando interno cria precedência. (Também demonstro a capacidade pouco conhecida de usar dois pontos duplos para efetivamente ser um comentário, o que também funciona bem em arquivos em lote. Tecnicamente, em arquivos em lote, ele é processado como um rótulo que não pode ser alcançado pelo GOTO e termina sendo mais rápido que o comando REM.)

C: \ algo> md cd
C: \ algo> eco eco subdir >> cd \ a.bat
C: \ algo> md \ a
C: \ alguma coisa> . \ Cd \ a.bat
subdir

C: \ algo> : Isso foi executado a partir do subdiretório
C: \ algo> cd \ a
C: \ a> :: Isso mudou meu diretório atual, então o cd teve precedência

Atualização: Após mais experiências, descobri que o comando cd interno só tem precedência sobre o sistema de arquivos se o diretório especificado não incluir um ponto. Portanto, se você tiver um diretório chamado " a.bat ", poderá executar " **cd\a.bat**" e o arquivo em lotes será executado.

Essa exploração de comportamentos menos comuns (uma vez que a maioria dos diretórios provavelmente não possui períodos) me levou a atualizar minhas descobertas. Acontece que o comando cd está realmente se comportando mais semelhante ao comando copy do que eu pensava inicialmente.

Embora eu inicialmente pensasse que os comandos cd e copy estavam se comportando de maneira diferente, agora descobri que isso se deve ao padrão dos nomes que eu estava fornecendo. Ainda assim, revisei meus resultados anteriores e determinei que meus testes documentados anteriores ajudam a mostrar algumas das diferenças entre o que acontece quando um nome inclui um período e uma extensão e quando não. Portanto, ainda estou incluindo minhas descobertas mais antigas abaixo (a maioria inalterada, mas com algumas atualizações muito pequenas, então o que eu digo é preciso).

Aqui está um exemplo de demonstração de cópia , com um caminho completo, não usa a mesma precedência (favorecendo o comando interno) que o cd quando nenhuma extensão é usada:

C: \ algo> raiz do eco do eco >> \ try.bat
C: \ algo> md copy
C: \ algo> subdiretório echo eco >> copiar \ try.bat
C: \ algo> . \ Copy \ try.bat é executado a partir de o subdiretório
subdiretório

C: \ something> copy \ try.bat
subdiretório

C: \ something> :: Hein? Por que isso não substituiu e foi executado a partir da raiz?
C: \ something> :: Aparentemente, o comando de cópia interno não tinha prioridade sobre a verificação de um subdiretório e nome de arquivo completo (mesmo que o comando cd interno tenha prioridade, quando o diretório não possui extensão)
C: \ something> ::
C: \ algo>:: Outro teste: posso adicionar períodos inúteis no final
C: \ algo> . \ Copy .. \ try.bat
subdiretório

C: \ algo> :: Ok, ótimo. Mas isso não verificará o subdiretório:
C: \ something> copy .. \ try.bat
        1 arquivo (s) copiado.

C: \ something> :: Isso executou o comando de cópia interna

Minhas descobertas iniciais indicaram que esses resultados demonstram que o shell da linha de comando dá prioridade:

  • ao sistema de arquivos (em vez do comando de cópia interno ) ao especificar uma barra invertida logo após o nome do comando interno
  • ao comando cd interno (em vez do sistema de arquivos) ao especificar uma barra invertida logo após o nome do comando interno.
  • ao comando de cópia interna (em vez do sistema de arquivos) ao especificar um ponto logo após o nome do comando interno.

Isso demonstra claramente que o comportamento não é consistente entre o comando copy (com um nome de arquivo completo incluindo uma extensão) e o comando cd (sem uma extensão como parte do nome do diretório). Ao usar uma barra invertida, o comando copy (com a extensão completa do nome do arquivo) verificará primeiro o sistema de arquivos, mas o comando cd não (se o diretório não contiver uma extensão).

(Atualização: no começo, achei que a inconsistência se baseava em comportamentos diferentes entre os programas. Mais tarde, descobri que a inconsistência existia, mas foi causada mais pelos parâmetros fornecidos.)

Na verdade, mesmo esses pontos não são totalmente precisos, mesmo que eu pareça demonstrar todas as coisas que acabei de dizer. O problema é que essa lista de pontos de bala não é precisa o suficiente para ser completamente precisa. (Deixei as coisas imprecisas para que esses itens pudessem ser comparados com relativa facilidade e verificados com relativa facilidade.)

No entanto, para ser mais preciso, o primeiro ponto deve apontar que o shell da linha de comando dá prioridade:

  • ao sistema de arquivos (em vez do comando de cópia interno ) ao especificar uma barra invertida e o restante do caminho completo, logo após o nome do comando interno

A seguir, demonstrarei por que estou fazendo essa distinção:

C: \ em outro lugar> elevação de UAC de eco necessária para esta linha >> \ needext
C: \ em outro lugar> elevação de UAC de eco necessária para esta linha >> \ needext.bat
C: \ em outro lugar> md. \ Copy
C: \ em outro lugar> echo @ eco subdir >> cópia \ needext.bat
C: \ em outros lugares> . \ copiar \ needext
subdir

C: \ em outros lugares> copiar \ needext.bat
subdir

C: outro local> \ copy \ needext
        arquivo 1 (s) copiado.

C: \ noutro lugar: :: UAC também é necessário para as próximas linhas
C: \ noutro lugar> del \ needext
C: \ noutro lugar> del \ needext.bat

(Observe que o último comando de cópia procurou o arquivo chamado \ needext , porque o comando de cópia interno foi usado. O arquivo \ needext.bat foi criado apenas para ajudar a mostrar com facilidade que nunca foi usado pelas linhas de comando que incluíam a palavra cópia .)

Neste ponto, eu estabeleci alguma inconsistência (com o comportamento do comando copy ) quando uma barra invertida é usada ...

A seguir, demonstrarei que há alguma consistência entre esses comandos. (Portanto, há consistência ... um ... às vezes. Podemos ter apenas consistência, inconsistentemente.) O que mostrarei a seguir é que o comando cd se comporta como o comando copy quando um ponto é usado. O comando copy usa o comando interno e o 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
subdireta

C: \ algo \ ainda mais> md. \ test

C: \ algo \ ainda mais> md
. \ test Já existe um subdiretório ou arquivo. \ test.

C: \ something \ yetmore> :: Esse erro mostra que executamos o comando interno.
C: \ algo \ ainda mais> md .. \ test
C: \ algo \ ainda mais> md. \ Cd
C: \ algo \ ainda mais> copiar. \ Md cd
. \ Md \ test.bat
        1 arquivo (s) copiado.

C: \ algo \ ainda mais> . \ Cd. \ Test
subdir

C: \ algo \ ainda mais> cd. \ Teste
C: \ algo \ ainda mais \ test> :: o comando interno trabalhou com um período
C: \ algo \ ainda mais \ test> cd ..
C: \ algo \ ainda mais> . \ cd .. \ test
subdir

C: \ algo \ ainda mais> cd .. \ test
C: \ algo \ teste> :: comando interno também teve prioridade quando dois períodos são usava

Portanto, durante a sessão de teste inicial, focada principalmente nos comandos cd e copy (com algum uso adicional de md e um pouco de del ), a única vez em que realmente tivemos o sistema de arquivos com prioridade foi com o comando copy , e então o comando copy O sistema de arquivos estava apenas tendo prioridade ao usar o caminho completo.

Após uma revisão subsequente, descobri que o comando cd também dava prioridade ao sistema de arquivos ao usar uma extensão. Pelo menos isso significa que os comandos internos estão sendo tratados um pouco mais consistentes entre si. No entanto, isso também significa que temos um comportamento diferente com base nos nomes dos objetos do sistema de arquivos (os arquivos ou diretórios). Parece que o comportamento está usando alguma lógica interna muito, muito obscura. Portanto, contar com esse comportamento para funcionar em diferentes sistemas operacionais é algo que eu provavelmente consideraria inseguro .

TOOGAM
fonte
"O comportamento que você descreve é ​​consistente para todos os comandos internos ao interpretador de linha de comando." ipconfigpor exemplo, também funciona.
Jonas Köritz 06/06
@ JonasKöritz: Não. Você pode colocar uma barra (encaminhada) logo após o comando " IPConfig " e isso funcionará, por exemplo IPCONFIG/ALL. No entanto, não era disso que eu estava falando. " O comportamento que você descreve " (na sua pergunta) era o comportamento de colocar um ponto logo após o nome do comando. Se eu digitar IPConfig., recebo um erro sobre um comando não ser encontrado. Da mesma forma (embora isso não esteja relacionado ao comportamento que você estava descrevendo), se eu digitar IPCONFIG\ALL, posso executar um .\IPCONFIG\ALL.BATarquivo personalizado que criei. Portanto /, não são tratados como .ou `\`
TOOGAM 06/06
1
Aceitarei sua resposta para apreciar o trabalho e a pesquisa necessários para criá-lo!
Jonas Köritz 06/06
2
@Calchas Teste simples - tente executar copy.exeou copy.comno cmd. Não funciona - não é um executável.
Luaan 8/06/16
1
@Luann: Em relação ipconfig, discordo de sua conclusão. Esta pergunta é sobre o que é digitado no início de uma linha de comando. O Windows / DOS identifica os executáveis ​​por extensão de nome de arquivo, portanto você não pode executar um programa chamado "ipconfig" sem uma extensão (no Windows, diferente do Unix que permite isso). Quanto ao próximo comentário, não sei quem é "Calchas". (Quando você especifica um sinal de arroba, geralmente são os primeiros caracteres de um usuário que aparece em outro lugar da página.) Concordo que a execução " copy.exe" utilizará o copycomando interno (e pass .exe). (Você pode executar .\copy.exe)
TOOGAM
41

Você assume que um nome de comando e seus argumentos devem ser separados por um espaço, especificamente, mas isso não é verdade. Desde que a chamada possa ser interpretada sem ambiguidade, a chamada é válida.

Neste caso, o primeiro argumento começa com .e .não pode ser parte do nome do comando, então cde ..são simplesmente analisado como dois tokens separados.

Geralmente, seu primeiro argumento começa com um caractere alfabético (por exemplo, o início de um caminho), portanto, ele "sangra" no nome do seu comando e causa um erro ... mas isso não é um problema de sintaxe. É semântico.

Você pode ver o mesmo efeito trabalhando com outros comandos, incluindo echo:

echo...
..

Nesse caso, obtemos apenas dois períodos porque o echopróprio comando possui uma regra especial , de modo que o seguinte:

echo .

ou, por extensão, esta:

echo.

gera apenas uma linha vazia. É uma conveniência. Aparentemente, isso foi implementado ignorando um período inicial no argumento.

Ei, isso é DOS / lote. Você quer sanidade? : D

Raças de leveza em órbita
fonte
2
Eu assumi isso porque ele é único para a linha de comando do Windows, o bash por exemplo, não irá permitir que você façacd..
Jonas Koritz
47
@ JonasKöritz: Esse é um programa completamente diferente em um sistema operacional totalmente diferente. Minha bicicleta não permite que cd..seja :)
Leveza raças em órbita
15
@ JonasKöritz:alias cd..='cd ..'
mouviciel
5
@LightnessRacesinOrbit: Originalmente, era um atalho para filtrar .e ..que aparece como diretórios em todos os outros diretórios e, até onde eu sei, nunca pretendia captar mais do que isso. Na verdade, eu considero o oculto modelado como atributo de arquivo um design mais limpo do que ter implícito o nome do arquivo.
Joey
4
@ joey - Eu acho que o ponto mais relevante não é que a abordagem do DOS era mais simples, é que o DOS não permitia .nomes de arquivos , o que significava que não poderia fazer parte do nome de um comando, portanto, deve ter sido parte do argumento . Mesmo se o DOS tivesse dividido o comando em argumentos, como os shells do Unix, ainda assim colocaria um .após o comando no primeiro argumento, porque não faria sentido colocar um caractere inválido no nome do comando.
Jules
19

O cd..comando está correto e foi definido assim no intérprete de comando original command.comque mais tarde foi nomeado cmd.exe.

O intérprete de comando sabe como processar cd.., porque .é um caractere especial, assim como \.

Overmind
fonte
8
Acho que o principal problema é que o comando não pode ser "sintaticamente incorreto" porque a sintaxe não é formalmente especificada em nenhum lugar ; portanto, se a implementação principal (cmd.exe e / ou MS-DOS) o aceitar, ele deverá estar correto.
grawity
3
Além disso, o CD não é um programa, mas um comando interno. Semelhante ao Echo, que também é um comando interno, ele não precisa ter espaço para funcionar. echo.funciona da mesma maneira, o que imprimirá uma linha vazia.
LPChip
2
@Overmind ecoam não quer trabalhar, então é o mesmo com cd, eco, md, etc.
LPChip
2
@ JonasKöritz, .não é descartado, mas apenas um espaço é adicionado. md.teste md .testtanto criar o diretório .test. Digitando cd.teste cd .testvai mudar para o diretório .test.
Daniel.neumann 06/06/19
6
@ JonasKöritz: Porque a sintaxe nunca foi um argumento de espaço de comando.
Corridas de leveza em órbita
11

É um hack de compatibilidade com versões anteriores.

O interpretador de linha de comando foi projetado para ser compatível com os comandos do interpretador de comandos original do MSDOS, que foi projetado para ser compatível com o interpretador de comandos CP / M. Nem o CP / M nem o MSDOS permitiram um .nome de arquivo (foi interpretado como um separador entre duas partes do nome do arquivo, o nome base e a extensão). Isso significava que (pelo menos para versões anteriores do DOS), o interpretador de comando poderia identificar isso se atingisse um '.' (ou qualquer outro caractere ilegal em um nome de arquivo) passou o final do nome do comando e entrou nos argumentos do comando. Isso era comumente usado no DOS e no CP / M - por exemplo, dir/wera um comando muito comum, equivalente ao dir /wsignificado de listar arquivos em um formato horizontal.

Hoje em dia, '.' pode aparecer nos nomes de arquivos. Isso causa algumas complicações em como analisar comandos, mas o shell ainda identifica um .que não faz parte de um nome de arquivo exato como sendo o início dos argumentos. Isso é necessário em grande parte porque milhões de usuários se acostumaram a digitar cd..ou possuem um grande número de arquivos em lote contendo esse echo.ou qualquer outro número de comandos semelhantes.

Jules
fonte