86

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

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

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

эхо ..

4 ответа4

105

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

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

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

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

Теперь также задан вопрос о команде echo : это необычное исключение, я думаю, что echo. довольно хорошо известен специалистам DOS. Это, вероятно, было задокументировано. Поведение, по крайней мере, в CMD Win7, заключается в том, что если команда начинается с « echo. », То первый период игнорируется. Итак, « echo..hi » превращается в вывод « .hi ». Причина этого в том, что « echo. » Можно использовать для печати пустой строки. В отличие от Unix, вы можете сделать это, просто запустив команду « echo ». Однако в DOS выполнение команды « echo » само по себе выведет текущую настройку « 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:\ что-то> MD CD
C:\ something> echo echo subdir >> cd\ a.bat
C:\ что-то> MD \ A
C:\ что-то> . \ Cd \ a.bat
подкаталог

C:\ что-то> :: Это побежал из subdir
C:\ что-то> CD \ A
C:\ a> :: Это изменило мой текущий каталог, поэтому cd имел приоритет

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

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

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

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

C: \thing > echo echo root >> \try.bat
C: \ что-то> копия md
C: \ что-то> подкаталог echo echo >> copy \try.bat
C: \ что-то> . \ Copy \try.bat запускается из подкаталога
подкаталог

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

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

C: \ что-то> :: Хорошо, отлично.Но тогда это не проверит подкаталог:
C: \ что-то> копировать .. \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
подкаталог

C:\elsewhere> copy \needext.bat
подкаталог

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:\ что-то> мкр.

C:\ что-то> компакт-диск.

C:\ то \ yetmore> мкр \ мкр.
C:\ что-то \ butmore> echo echo subdir >> md \ test.bat
C:\ что-то \ все же> . \ Md . \ Test
подкаталог

C:\ что-то \ все же> md. \ Test

C:\ что-то \ все же> md. \ Test
Подкаталог или файл. \ Test уже существует.

C:\ something \ Yetmore> :: Эта ошибка показывает, что мы выполнили внутреннюю команду.
C:\ что-то \ все же> md .. \ test
C:\ что-то \ все же> MD . \ CD
С:\ что-то \ все же> копировать. \ Md cd
. \ Мкр \ test.bat
        1 файл (ов) скопирован.

C:\ что-то \ все же> . \ Cd. \ Test
подкаталог

C:\ что-то \ все же> cd. \ Test
C:\ что-то \ whatmore \ test> :: внутренняя команда работала с одним периодом
C:\ что-то \ все же \ тест> компакт-диск ..
C:\ что-то \ все же> . \ Cd .. \ test
подкаталог

C:\ что-то \ все же> компакт-диск .. \ тест
C:\ something \ test> :: internal команда также имеет приоритет при использовании двух периодов

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

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

41

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

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

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

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

echo...
..

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

echo .

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

echo.

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

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

19

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

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

11

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

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

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

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .