Почему «cd ..» работает в командной строке Windows?

86

При наборе текста cd..без пробела между cdи ..командная строка Windows с радостью переключится в родительскую папку. Есть ли объяснение этому поведению? Команда не соответствует стандартному форматуcommand<space>arguments

Работать, но не должен?

Кроме того, почему это не создает последовательных результатов?

эхо ..

Йонас Кёриц
источник
24
Предпосылка вашего вопроса, кажется, нарушена. Можете ли вы предоставить какие-либо доказательства для вашего утверждения, что это синтаксически неверно?
Гонки легкости на орбите
13
Я не думаю, что «command <space> arguments» когда-либо был стандартным форматом в cmd (или любом из его предшественников); рассмотрим, например, dir/aили похожий синтаксис VMS.
Гравитация
6
CD очень особенный. Вы можете печатать cd c:\program filesбез кавычек, и это все еще работает
phuclv
20
Вот очень интересная статья, которая объясняет причуды логики оболочки Windows, и то, что это может вызвать хаос: thedailywtf.com/articles/The-Core-Launcher
vsz
3
Почему cd..работает? Потому что Microsoft столкнулась с проблемой явно заставить его работать. cdэто команда, встроенная в интерпретатор команд Windows, и Microsoft может заставить их интерпретатор делать что угодно. (В качестве другого примера, cdтакже не нужно
заключать в кавычки

Ответы:

106

Как отмечают некоторые другие ответы / комментарии, идея о том, что после команды должен быть пробел, неверна. Хорошо известным примером является то, что вы можете вводить косую черту после команды, не используя пробел.

Тем не менее, есть другое поведение, которое немного менее понятно, и допускает " cd..", о котором вы спрашиваете. Такое поведение также позволяет " cd\" работать.

Поведение, которое вы описываете, является совместимым для всех команд, встроенных в интерпретатор командной строки. Если у вас есть определенные символы, включая точку, косую черту или обратную косую черту, то проверяются предыдущие символы, чтобы определить, являются ли они командой, которая является внутренней для оболочки «интерпретатора командной строки» (CMD.EXE или его предшественника COMMAND.COM ).

Это может быть сделано перед проверкой, может ли слово относиться к файлу или подкаталогу. Это верно для cdкоманды. К сожалению, при создании образца я обнаружил, что с copyкомандой этого не происходит , поэтому результаты не всегда совпадают: они не обязательно совпадают со всеми внутренними командами. Я не продолжил свой поиск, чтобы также сравнить (много) другие командные строки, delи dirпоэтому я просто предлагаю быть предельно осторожным, если вы пытаетесь полагаться на то, что происходит без пробела.

Теперь также задан вопрос о команде echo : это необычное исключение, которое, я думаю echo., довольно хорошо известно специалистам DOS. Это, вероятно, было задокументировано. Поведение, по крайней мере, в CMD Win7 , заключается в том, что если команда начинается с " echo.", то первый период игнорируется. Таким образом, " echo..hi" превращается в вывод " .hi". Причина этого в том, что « echo.» можно использовать для печати пустой строки. В отличие от Unix, вы можете сделать это, просто запустив команду " echo". Тем не менее, в DOS, выполнение команды " echo" само по себе выведет текущую настройку " эхо ". Точно так же DOS рассматривает " Echo *Off*" и "Echo *On*"как специальные значения, которые изменяют текущую настройку эха. Если вы действительно хотите напечатать слово" Off", то" Echo.Off"добьется цели (по крайней мере, с достаточно недавними версиями интерпретатора командной строки CMD от Microsoft .)

Так что, по крайней мере, у echoкоманды есть полуразумное объяснение. Что касается остальных команд, я привык думать, что внутренние команды имеют приоритет. Однако, когда я попытался сделать несколько тестов, я обнаружил, что это довольно противоречиво. Я демонстрирую это на нескольких примерах, которые я задокументировал здесь.


Вот несколько примеров. Я использовал командную строку с повышенными правами, чтобы UAC не обращал на меня внимание при записи в корневой каталог. Это было сделано с помощью Microsoft Windows 7 CMD.EXE. Я подозреваю, что поведение может отличаться в других версиях, таких как COMMAND.COM из более старых версий MS-DOS или программного обеспечения, выпущенного другими компаниями (DR-DOS's COMMAND.COM).

(Этот ответ уже довольно длинный, поэтому я не включаю команды, чтобы очистить весь беспорядок, который я сделал в моей файловой системе. Есть небольшая часть очистки, но не очень.)

Вот пример, который доказывает, что внутренняя команда создает приоритет. (Я также демонстрирую довольно малоизвестную способность использовать двойное двоеточие, чтобы эффективно быть комментарием, который также хорошо работает в пакетных файлах. Технически, в пакетных файлах, он обрабатывается как метка, которая не может быть достигнута GOTO, и заканчивается быть быстрее, чем команда REM.)

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

C: \ something> :: Это бежало из подкаталога
C: \ something> cd \ a
C: \ a> :: Это изменило мой текущий каталог, поэтому cd имел приоритет

Обновление. После дальнейших экспериментов я обнаружил, что внутренняя команда cd имеет приоритет над файловой системой, только если указанный каталог не содержит точку. Так что если у вас есть каталог с именем « a.bat », то вы можете запустить « **cd\a.bat**» и пакетный файл запустится.

Это исследование менее распространенного поведения (так как большинство каталогов, вероятно, не содержат периодов) привело меня к обновлению моих выводов. Оказывается, что команда cd на самом деле ведет себя более похоже на команду copy, чем я изначально думал.

Хотя я сначала думал, что команды cd и copy ведут себя по-разному, теперь я понял, что это из-за структуры имен, которые я предоставлял. Тем не менее, я просмотрел свои предыдущие результаты и определил, что мои ранее задокументированные тесты помогают показать некоторые различия между тем, что происходит, когда имя включает точку и расширение, и когда это не так. Итак, я все еще включаю свои старые выводы ниже (в основном без изменений, но с некоторыми очень незначительными обновлениями, поэтому то, что я говорю, является точным).

Вот пример, демонстрирующий, что копия с полным путем не использует тот же приоритет (в пользу внутренней команды), что и cd, когда расширение не используется:

C: \ thing > эхо-корень эха >> \ try.bat
C: \ что-то> копия md
C: \thing > подкаталог эхо-эха >> копия \ try.bat
C: \ что-то> . \ Copy \ try.bat запускается из подкаталог
подкаталог

C: \ что - то> скопировать \ try.bat
подкаталоге

C: \ что - то> :: А? Почему это не переопределить и не запустить из корня?
C: \ something> :: Очевидно, что внутренняя команда копирования не имеет приоритета над проверкой подкаталога и полного имени файла (даже если внутренняя команда cd имела приоритет, когда каталог не имеет расширения)
C: \ кое-что> ::
C: \ что-то>:: Еще один тест: я могу добавить бесполезные периоды в конце
C: \ something> . \ Copy .. \ try.bat
подкаталог

C: \ something> :: Хорошо, отлично. Но тогда это не проверит подкаталог:
C: \thing > copy .. \ try.bat
        1 файл (ов) скопирован.

C: \ что-то> :: Это запустило команду внутреннего копирования

Мои ранние результаты показали, что эти результаты показывают, что командная строка дает приоритет:

  • в файловую систему (вместо внутренней команды копирования ) при указании обратной косой черты сразу после имени внутренней команды
  • к внутренней команде cd (вместо файловой системы) при указании обратной косой черты сразу после имени внутренней команды.
  • к внутренней команде копирования (вместо файловой системы) при указании периода сразу после имени внутренней команды.

Это ясно демонстрирует, что поведение не согласовано между командой copy (с полным именем файла, включая расширение) и командой cd (без расширения как части имени каталога). При использовании обратной косой черты команда copy (с полным расширением имени файла) сначала проверит файловую систему, а команда cd - нет (если каталог не содержит расширения).

(Обновление: сначала я думал, что несоответствие было основано на различном поведении между программами. Позже я обнаружил, что несоответствие действительно существовало, но было вызвано больше из предоставленных параметров.)

На самом деле, даже эти пункты не совсем точны, хотя я, кажется, только что продемонстрировал каждую отдельную вещь, которую я только что сказал. Проблема в том, что список пунктов не достаточно точен, чтобы быть полностью точным. (Я оставил вещи неточными, чтобы можно было сравнительно легко сравнивать эти пункты и проверять их относительно легко.)

Тем не менее, чтобы быть более точным, первый пункт должен указать, что оболочка командной строки дает приоритет:

  • к файловой системе (вместо внутренней команды копирования ) при указании обратной косой черты, а затем оставшейся части полного пути сразу после имени внутренней команды

Следующее покажет, почему я делаю это различие:

C: \ elsewhere> эхо- повышение UAC, необходимое для этой строки >> \ needext
C: \ elsewhere> эхо- повышение UAC, необходимое для этой строки >> \ needext.bat
C: \ elsewhere> md. \ Copy
C: \ elsewhere> echo @ Echo subdir >> copy \ needext.bat
C: \ elsewhere> . \ Copy \ needext
subdir

C: \ elsewhere> copy \ needext.bat
subdir

C: \ elsewhere> copy \ needext
        1 файл (ов) скопирован.

C: \ elsewhere> :: UAC также необходим для следующих строк
C: \ elsewhere> del \ needext
C: \ elsewhere> del \ needext.bat

(Обратите внимание, что последняя команда копирования искала файл с именем \ needext , поскольку использовалась внутренняя команда копирования . Файл \ needext.bat был создан только для того, чтобы легко показать, что он никогда не использовался командными строками, включающими слово copy .)

На этом этапе я установил некоторую несогласованность (с поведением команды копирования ), когда используется обратный слеш ...

Далее я продемонстрирую, что между этими командами есть некоторая согласованность. (Итак, есть последовательность ... хм ... иногда. У нас может быть только непротиворечивость, непоследовательность.) Далее я покажу, что команда cd ведет себя скорее как команда копирования, когда используется точка. Команда copy использует внутреннюю команду, как и команда cd .

C: \ something> md. \ Yetmore

C: \ Some > CD. \ Yetmore

C: \thing \ Yetmore> md . \ Md C: \thing
\ Yetmore> эхо- эхо subdir >> md \ test.bat
C: \ что-то \ Yetmore> . \ md. \ test
subdir

C: \ что-то \ Yetmore> md. \ test

C: \thing \ Yetmore> md. \ test Подкаталог
или файл. \ test уже существует.

C: \ something \ Yetmore> :: Эта ошибка показывает, что мы выполнили внутреннюю команду.
C: \ something \ Yetmore> md .. \ test
C: \ Чем-то \ butmore> md. \ Cd
C: \thing \ Yetmore> copy. \ Md cd
. \ Md \ test.bat
        1 файл (ов) скопирован.

C: \ Чем-то \ whatmore> . \ Cd. \ Test
subdir

C: \ something \ Yetmore> cd. \ Test
C: \thing \ Yetmore \ test> :: внутренняя команда работала с одним периодом
C: \ something \ Yetmore \ test> cd ..
C: \ что-то \ butmore> . \ cd .. \ test
subdir

C: \thing \ Yetmore> cd .. \ test
C: \ Чем- то \ test> :: internal команда также имеет приоритет, когда два периода используемый

Итак, во время начального сеанса тестирования, который в основном был сосредоточен на командах cd и copy (с некоторым дополнительным использованием md и немного del ), единственный раз, когда у нас действительно была приоритетность файловой системы, была команда copy , а затем файловая система имела приоритет только при использовании полного пути.

После последующего просмотра я обнаружил, что команда cd также отдает приоритет файловой системе при использовании расширения. По крайней мере, это означает, что внутренние команды обрабатываются немного более согласованно друг с другом. Однако это также означает, что мы получаем другое поведение в зависимости от имен объектов файловой системы (файлов или каталогов). Кажется, что в поведении используется какая-то действительно очень непонятная внутренняя логика. Поэтому, полагаясь на такое поведение для работы в разных операционных системах, я бы посчитал это небезопасным .

TOOGAM
источник
«Поведение, которое вы описываете, соответствует всем командам, внутренним для интерпретатора командной строки». ipconfigнапример тоже работает.
Йонас Кёриц
@ JonasKöritz: Нет. Вы можете поставить (прямую) косую черту сразу после команды " IPConfig ", и это будет работать, например IPCONFIG/ALL. Однако это не то, о чем я говорил. « Поведение, которое вы описываете » (в вашем вопросе), было поведением точки после имени команды. Если я печатаю, IPConfig.я получаю сообщение об ошибке, что команда не найдена. Точно так же (хотя это не относится к описанному вами поведению), если я наберу IPCONFIG\ALLтекст, я могу запустить .\IPCONFIG\ALL.BATсозданный мной файл. Так /что не обращаются как .или `\`
TOOGAM
1
Я приму ваш ответ, чтобы оценить работу и исследования, необходимые для ее создания!
Йонас Кёриц
2
@Calchas Простой тест - попробуйте выполнить copy.exeили copy.comв cmd. Это не работает - это не исполняемый файл.
Луаан
1
@Luann: Что касается ipconfig, я не согласен с вашим выводом. Этот вопрос о том, что напечатано в начале командной строки. Windows / DOS идентифицирует исполняемые файлы по расширению имени файла, поэтому вы не можете запустить программу под названием «ipconfig» без расширения (в Windows, в отличие от Unix, который разрешает это). Что касается следующего комментария, я не знаю, кто такой "Calchas". (Когда вы указываете знак «at», обычно это следующие первые символы пользователя, который появляется в другом месте на странице.) Я согласен, при запуске « copy.exe» будет использоваться внутренняя copyкоманда (и pass .exe). (Вы можете бежать .\copy.exe)
TOOGAM
41

Предполагается, что имя команды и ее аргументы должны быть разделены пробелом, но это не так. Пока вызов может быть однозначно интерпретирован, вызов действителен.

В этом случае, первый аргумент начинается с .и .не может быть частью имени команды, так cdи ..просто обрабатывается как два отдельных лексем.

Обычно ваш первый аргумент начинается с буквенного символа (например, с начала пути), поэтому он «сливается» с именем вашей команды и вызывает ошибку… но это не проблема синтаксиса. Это семантический.

Вы можете увидеть тот же эффект при работе с другими командами, в том числе echo:

echo...
..

В этом случае мы получаем только два периода, потому что у echoсамой команды есть специальное правило , так что следующее:

echo .

или, по сути, это:

echo.

выводит только пустую строку. Это удобство. По-видимому, это было реализовано путем игнорирования начального периода в аргументе.

Привет, это DOS / Batch. Вы хотите здравомыслие? : D

Гонки легкости на орбите
источник
2
Я предположил это, потому что он уникален для командной строки Windows, например, bash не позволит вам это сделатьcd..
Jonas Köritz
47
@ JonasKöritz: Это совершенно другая программа в совершенно другой операционной системе. Мой велосипед тоже не позволяет cd..:)
гонки на легкости на орбите
15
@ JonasKöritz:alias cd..='cd ..'
mouviciel
5
@LightnessRacesinOrbit: Первоначально это был ярлык фильтрации .и ..которые отображаются в виде каталогов в любой другой директории , и, насколько я знаю , никогда не был предназначен , чтобы поймать больше , чем это. Я на самом деле считаю скрытность, смоделированную как атрибут файла, более чистой конструкцией, чем то, что она неявно вытекает из имени файла.
Джои
4
@joey - я думаю, что более важным моментом является не то, что подход DOS был проще, а то, что DOS не допускал .имен файлов , что означало, что он не мог быть частью имени команды, поэтому должен был быть частью аргумента . Даже если бы DOS разделил команду на аргументы, как это делают оболочки Unix, он все равно .поместил бы после команды в первый аргумент, потому что не было бы смысла вставлять недопустимый символ в имя команды.
Жюль
19

Команда cd..верна, и она была определена так же, как и в оригинальном интерпретаторе команд, command.comкоторый впоследствии был назван cmd.exe.

Интерпретатор команд знает, как обрабатывать cd.., потому что .это специальный символ, как и \.

Сверхразум
источник
8
Я предполагаю, что основная проблема заключается в том, что команда не может быть «синтаксически неправильной», поскольку синтаксис нигде не указан формально , поэтому, если его принимает основная реализация (cmd.exe и / или MS-DOS), она должна быть правильной.
Гравитация
3
Кроме того, CD - это не программа, а внутренняя команда. Подобно Echo, который также является внутренней командой, ему не нужно места для работы. echo.работает так же хорошо, что будет печатать пустую строку.
LPChip
2
@Overmind echoe также не будет работать, поэтому то же самое с CD, echo, md и т. Д.
LPChip
2
@ JonasKöritz, .не опускается, а просто добавляется пробел. md.testи md .testоба создают каталог .test. Набрав cd.testи cd .testизменится в каталог .test.
daniel.neumann
6
@ JonasKöritz: потому что синтаксис никогда не был аргументом пространства команд.
Гонки легкости на орбите
11

Это взлом обратной совместимости.

Интерпретатор командной строки предназначен для обратной совместимости с командами исходного интерпретатора команд MSDOS, который был разработан для обратной совместимости с интерпретатором команд CP / M. Ни CP / M, ни MSDOS не допускали использование a .в имени файла (это интерпретировалось как разделитель между двумя частями имени файла, базовым именем и расширением). Это означало, что (по крайней мере, для ранних версий DOS) интерпретатор команд мог определить это, если достигнет «.» (или любой другой символ, который был недопустим в имени файла), он прошел конец имени команды и был в аргументах команды. Это довольно часто использовалось как в DOS, так и в CP / M - например, это dir/wбыла очень распространенная команда, эквивалентная dir /wзначению перечислять файлы в горизонтальном формате.

В наше время, '.' может появиться в именах файлов. Это вызывает некоторые сложности в том, как анализировать команды, но оболочка все еще идентифицирует, .что не является частью точного имени файла, как начало аргументов. Это необходимо в значительной степени потому, что миллионы пользователей привыкли печатать cd..или имеют большое количество командных файлов, содержащих эту echo.или любую другую аналогичную команду.

Жюль
источник