Чому "cd .." працює в командному рядку Windows?


86

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

Working but shouldn't?

Також, чому це не створює послідовних результатів?

echo..


24
Передумова вашого питання, здається, порушена. Чи можете ви надати будь-які докази того, що це синтаксично неправильно?
Lightness Races in Orbit

13
Я не думаю, що "аргументи & lt; space & gt;" ніколи не були стандарт формат у cmd (або будь-якому з його попередників); розглянемо, наприклад dir/a або аналогічний синтаксис VMS.
grawity

6
cd дуже особливий. Можна ввести cd c:\program files без лапок і все одно працює
phuclv

20
Ось дуже цікава стаття, в якій пояснюються примхи логіки оболонки Windows, і який хаос може викликати: thedailywtf.com/articles/The-Core-Launcher
vsz

3
Чому cd.. працювати? Тому що Microsoft пройшла через труднощі з явною його роботою. cd є командою, вбудованою в командний інтерпретатор Windows, і Microsoft може зробити їх перекладачем те, що вони хочуть. (Як інший приклад, cd також не потрібно цитувати навколо каталогів з пробілами в назві.)
jamesdlin

Відповіді:


105

Як відзначають деякі інші відповіді / коментарі, ідея про те, що після команди не має бути пробілу. Добре відомим прикладом є те, що ви можете вводити косу риску після команди, не потребуючи пробілу спочатку.

Однак існує інша поведінка, яка трохи менш зрозуміла і дозволяє " cd.. "про що ви просите. Така поведінка також дозволяє" cd\ " працювати.

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

Це можна зробити, перш ніж перевіряти, чи може слово посилатися на файл або підкаталог. Це справедливо для cd команду. Трагічно, коли я роблю зразок, я виявив, що цього не відбувається з copy команду, тому результати є невідповідними: вони не обов'язково збігаються з усіма внутрішніми командами. Я не продовжив свій пошук, щоб порівняти (багато) інші рядки команд del і dir, тому я просто пропоную бути надзвичайно обережним, якщо ви намагаєтеся покладатися на те, що відбувається без простору.

Тепер питання також задали про луна command: Це незвичайне виключення, в якому я думаю echo. досить відома експертам DOS. Це, ймовірно, було задокументовано. Поведінка, принаймні, у Win7 CMD це те, що якщо команда починається з " echo. ", тоді перший період ігнорується. Отже," echo..hi "перетворюється на вихід" .hi ". Причиною цього є те, що" echo. "можна використовувати для друку порожнього рядка. На відміну від Unix, ви можете зробити це, просто виконавши" echo "Команда сама по собі. echo "команда сама виведе поточний" луна "налаштування. Аналогічно, DOS розглядає" Echo *Off* "і" Echo *On* "як спеціальні значення, що змінюють поточну ехо-налаштування. Якщо ви дійсно хочете надрукувати слово" Off ", потім " Echo.Off "робить свою справу (принаймні з недавніми версіями Microsoft. \ t CMD інтерпретатор командного рядка.)

Отже, принаймні echo команда має напів-розумне пояснення. Що стосується інших команд, то я вважав, що внутрішні команди мають пріоритет. Однак, коли я спробував зробити деякі тести, я виявив, що насправді є досить непослідовним. Я демонструю це через кілька прикладів, які я тут зафіксував.


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

(Ця відповідь є досить довгою, тому я не включаю команди для очищення всього безладу, який я зробив на моїй файловій системі.

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

C: \ t md cd
C: \ t луна echo subdir & gt; & gt; cd \ t
C: \ t md a
C: \ t cd \ t
subdir

C: \ t :: Це пробіг з підкаталоги
C: \ t cd \ t
C: a & gt; :: Що змінило мій поточний каталог, так cd пріоритет

Оновити: Після подальших експериментів я виявив, що внутрішні cd команда має перевагу над файловою системою, якщо вказаний каталог не містить періоду. Отже, якщо у вас є каталог з ім'ям " a.bat ", тоді ви можете запустити" **cd\a.bat** "і пакетний файл буде запущено.

Це вивчення менш поширеної поведінки (оскільки більшість каталогів, ймовірно, не мають періодів в них) змусило мене оновити свої висновки. Виявляється, що cd команда насправді веде себе більше схожою на копіювати команди, ніж я спочатку думав.

Хоча я спочатку думав cd і копіювати Команди поводилися по-іншому, я тепер зрозумів, що це відбувається через структуру імен, які я надаю. Тим не менш, я переглянув свої попередні результати і визначив, що мої раніше документировані тести допомагають показати деякі відмінності між тим, що відбувається, коли ім'я включає період і розширення, і коли це не відбувається. Отже, я до сих пір включаю мої старші висновки нижче (в основному незмінними, але з деякими дуже незначними оновленнями, так що те, що я кажу, є точним).

Ось приклад демонстрації копіювати , з повним контуром, не використовує той самий пріоритет (на користь внутрішньої команди), як cd коли не використовується розширення:

C: \ t echo echo root & gt; & gt; try.bat
C: \ t md copy
C: \ t підкаталог echo echo & gt; & gt; копіювати
C: \ t запускається з підкаталогу
підкаталог

C: \ t копіювати
підкаталог

C: \ t :: Так? Чому це не перекриває і не запускається з кореня?
C: \ t :: Мабуть, внутрішня копіювати команда не мала пріоритету над перевіркою на підкаталог і повне ім'я файлу (навіть якщо внутрішній cd команда має пріоритет, коли каталог не має розширення
C: \ t ::
C: \ t :: Ще один тест: я можу додати непотрібні періоди в кінці
C: \ t копію ..
підкаталог

C: \ t :: Добре, здорово. Але це не перевірить підкаталог:
C: \ t Копіювати ..
Скопійовано 1 файл (и).

C: \ t :: Вона виконала команду внутрішньої копії

Мої ранні результати показали, що ці результати демонструють, що оболонка командного рядка надає пріоритет:

  • до файлової системи (замість внутрішньої копіювати Команда) при вказівці зворотної косої відразу після імені внутрішньої команди
  • до внутрішнього cd Команда (замість файлової системи) при вказівці зворотної косої відразу після імені внутрішньої команди.
  • до внутрішнього копіювати команда (замість файлової системи) при заданні періоду відразу після імені внутрішньої команди.

Це наочно демонструє, що поведінка не відповідає копіювати команду (з повним іменем файлу, включаючи розширення) і cd (без розширення як частину імені каталогу). При використанні зворотної скісної риски копіювати команда (з повним розширенням файлу) спочатку перевірить файлову систему, але cd команда не буде (якщо каталог не містить розширення).

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

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

Однак, щоб бути більш точним, перший пункт має вказувати, що оболонка командного рядка надає пріоритет:

  • до файлової системи (замість внутрішньої копіювати команду), коли вказується зворотний слеш, і потім решту повного шляху, відразу після ім'я внутрішньої команди

Нижче буде показано, чому я роблю це відмінність:

C: в іншому місці & gt; луна Для цієї лінії потрібна висота UAC & gt; & gt; далі
C: в іншому місці & gt; луна Для цієї лінії потрібна висота UAC & gt; & gt; . \ t
C: в іншому місці & gt; md. \ t
C: в іншому місці & gt; луна Вкладок @Echo & gt; & gt; копіювати
C: в іншому місці & gt; . \ t
subdir

C: в іншому місці & gt; копіювати
subdir

C: в іншому місці & gt; копіювати
Скопійовано 1 файл (и).

C: в іншому місці & gt; :: UAC також необхідний для наступних рядків
C: в іншому місці & gt; del
C: в іншому місці & gt; del \ t

(Зауважте, що останній копіювати команда шукала файл, званий далі , тому що внутрішній копіювати команда була використана. Файл . \ t було створено лише для того, щоб допомогти легко показати, що вона ніколи не використовувалася командними рядками, які включали слово копіювати .)

У цей момент я встановив деяку невідповідність (з поведінкою копіювати команда), коли використовується зворотний слеш ...

Далі я продемонструю, що між цими командами існує певна узгодженість. (Отже, є послідовність ... іноді. Ми можемо мати лише послідовність, непослідовність.) Те, що я покажу далі, це те, що cd команда веде себе досить як копіювати команда, коли використовується період. The копіювати команда використовує внутрішню команду, так само як і cd команду.

C: \ t md. \ t

C: \ t більше. \ t

C: щось більше & gt; md. \ t
C: щось більше & gt; луна echo subdir & gt; & gt; md test.bat
C: щось більше & gt; md. \ t
subdir

C: щось більше & gt; md. \ t

C: щось більше & gt; md. \ t
Підкаталог або файл.

C: щось більше & gt; :: Ця помилка показує, що ми запустили внутрішню команду.
C: щось більше & gt; md .. тест
C: щось більше & gt; md. \ t
C: щось більше & gt; копіювати. \ t
bd
Скопійовано 1 файл (и).

C: щось більше & gt; cd. \ t
subdir

C: щось більше & gt; cd. \ t
C: щось більше & gt; :: внутрішня команда працювала з одним періодом
C: щось більше & gt; cd ..
C: щось більше & gt; CD .. тест
subdir

C: щось більше & gt; cd .. тест
С: щось & gt; Команда :: internal також має пріоритет, коли використовуються два періоди

Отже, під час початкової сесії тесту, яка в основному орієнтована на cd і копіювати команд (з додатковим використанням md і трохи del ), єдиний раз, коли ми дійсно мали пріоритет у файловій системі, було з копіювати команду, а потім файлова система має тільки пріоритет при використанні повного шляху.

Після подальшого огляду я виявив, що cd команда також надала пріоритет файлової системи при використанні розширення. Принаймні це означає, що внутрішні команди обробляються трохи більш узгодженими один з одним. Однак, це також означає, що ми отримуємо різні поведінки на основі імен об'єктів файлової системи (файлів або каталогів). Здається, що поведінка використовує деякі дійсно, дуже неясні внутрішні логіки. Тому, розраховуючи на таку поведінку, щоб працювати в різних операційних системах, я, напевно, вважаю небезпечно зробити.


"Поведінка, яку ви описуєте, узгоджується з усіма внутрішніми командами інтерпретатора командного рядка." ipconfig наприклад працює теж.
Jonas Köritz

@ JonasKöritz: Ні. Ви можете помістити (вперед) косу чергу після команди " IPConfig "і це буде працювати, напр. IPCONFIG/ALL. Проте це не те, про що я говорив. " Поведінка, яку ви описуєте "(у вашому питанні) була поведінка розміщення періоду відразу після імені команди IPConfig. Потім я отримую помилку про команду, яка не знайдена. Аналогічно (хоча це не пов'язано з поведінкою, яку ви описували), якщо я набираю IPCONFIG\ALL тоді я можу запустити звичай .\IPCONFIG\ALL.BAT файл, який я зробив. Тому / Не розглядаються як . або \ t
TOOGAM

1
Я прийму Вашу відповідь, щоб оцінити роботу та дослідження, необхідні для її створення!
Jonas Köritz

2
Простий тест - спробуйте виконати copy.exe або copy.com у cmd. Це не працює - це не виконуваний файл.
Luaan

1
@Luann: Що стосується ipconfigЯ не згоден з вашим висновком. Це питання стосується того, що набрано на початку командного рядка. Windows / DOS ідентифікує виконувані файли за розширенням імені файлу, тому ви не можете запустити програму під назвою "ipconfig" без розширення (у Windows, на відміну від Unix, яка дозволяє це). Що стосується наступного коментаря, я не знаю, хто "Calchas". (Коли ви вказуєте знак підпису, наступні, як правило, перші символи користувача, які відображаються в іншому місці на сторінці.) Я згоден, працює " copy.exe "буде використовувати внутрішню copy команду (і передавати .exe ). (Ви можете запустити .\copy.exe )
TOOGAM

41

Ви припускаєте, що ім'я команди та її аргументи повинні бути розділені пропуском, зокрема, але це не так. Доки виклик може бути однозначно інтерпретований, виклик є дійсним.

У цьому випадку починається перший аргумент . і . не може бути частиною імені команди, тому cd і .. просто обробляються як дві окремі маркери.

Зазвичай, ваш перший аргумент почнеться з буквеного символу (наприклад, початок шляху), тому він буде "кровоточити" у вашій назві команди і викликатиме помилку ... але це не проблема синтаксису. Це семантичний.

Такий же ефект можна побачити при роботі з іншими командами, в тому числі echo:

echo...
..

У цьому випадку ми отримуємо тільки два періоди, тому що echo сама команда має спеціальне правило , так що наступне:

echo .

або, як наслідок, це:

echo.

виводить лише порожній рядок. Це зручність. Очевидно, він був реалізований, ігноруючи провідний період у аргументі.

Гей, це DOS / Batch. Ви хочете розум? : D


2
Я припустив це, тому що це унікальний для командного рядка Windows, Баш наприклад не дозволить вам зробити cd..
Jonas Köritz

47
@ JonasKöritz: Це зовсім інша програма на зовсім іншій операційній системі. Мій велосипед не дозволяє cd.. або :)
Lightness Races in Orbit

15
@ JonasKöritz: alias cd..='cd ..'
mouviciel

5
@LightnessRacesinOrbit: Спочатку це було скороченням фільтрування . і .. які відображаються як каталоги в будь-якому іншому каталозі, і наскільки я знаю, ніколи не мали на меті спіймати більше. Я насправді вважаю, що прихований-неї моделюється як атрибут файлу чистіший дизайн, ніж його неявно випливає з імені файлу.
Joey

4
@joey - Я думаю, що більш відповідним моментом є не те, що підхід DOS був більш простим, це те DOS не дозволила . у назвах файлів , що означало це не може бути частиною імені команди тому мали бути частиною аргументу . Навіть якщо DOS розділила команду на аргументи, як це роблять оболонки Unix, вона все одно розміщувала a . після команди в перший аргумент, тому що не має сенсу вводити невірний символ в ім'я команди.
Jules

19

The cd.. Команда є правильною і вона була визначена так, як у вихідному інтерпретаторі команд command.com який пізніше був названий cmd.exe.

Інтерпретатор команд знає, як обробляти cd.., оскільки . є спеціальним символом, точно так само \.


8
Думаю, головна проблема полягає в тому, що команда не може бути "синтаксично некоректною" через синтаксис офіційно не вказано ніде , отже, якщо основна реалізація (cmd.exe та / або MS-DOS) приймає її, то вона повинна бути правильною.
grawity

3
Крім того, компакт-диск - це не програма, а внутрішня команда. Подібно до Ехо, який також є внутрішньою командою, він не повинен мати місця для роботи. echo. працює так само добре, що роздрукує порожній рядок.
LPChip

2
Echoe не буде працювати, так що це те ж саме з cd, echo, md і т.д.
LPChip

2
@ JonasKöritz . не видаляється, а просто додається пробіл. md.test і md .test обидва створюють каталог .test. Введення тексту cd.test і cd .test перейдуть до каталогу .test.
daniel.neumann

6
@ JonasKöritz: Оскільки синтаксис ніколи не був аргументами командного простору.
Lightness Races in Orbit

11

Це зворотна сумісність.

Інтерпретатор командного рядка призначений для зворотної сумісності з командами з оригінального інтерпретатора команд MSDOS, який був розроблений для зворотної сумісності з інтерпретатором команд CP / M. Ні CP / M, ні MSDOS не дозволили a . в імені файлу (інтерпретувався як роздільник між двома частинами імені файлу, базовою назвою і розширенням). Це означало, що (принаймні для ранніх версій DOS), інтерпретатор команд міг би визначити, що, якщо він досяг '.' (або будь-який інший символ, який був неправомірним у назві файлу), він передав кінець імені команди і був у аргументах команди. Це досить часто використовувалося як в DOS, так і в CP / M - наприклад, dir/w була дуже поширеною командою, еквівалентною dir /w означає перелік файлів у горизонтальному форматі.

Сьогодні, '.' можуть з'являтися в іменах файлів. Це викликає деякі ускладнення, як розбирати команди, але оболонку досі ідентифікує a . це не є частиною точного імені файлу, як початку аргументів. Це необхідно багато в чому тому, що мільйони користувачів звикли до друку cd.. або мають велику кількість пакетних файлів, що містять це або echo. або будь-яку кількість інших подібних команд.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.