Dlaczego „cd ..” działa w wierszu poleceń systemu Windows?

86

Podczas pisania cd..bez spacji między cdi ..wiersz polecenia systemu Windows z przyjemnością przełączy się do folderu nadrzędnego. Czy istnieje wyjaśnienie tego zachowania? Polecenie nie ma standardowego formatucommand<space>arguments

Pracuje, ale nie powinno?

Ponadto, dlaczego nie zapewnia to spójnych wyników?

Echo..

Jonas Köritz
źródło
24
Założenie twojego pytania wydaje się być zepsute. Czy możesz przedstawić dowód na to, że jest to niepoprawna składniowa?
Wyścigi lekkości na orbicie
13
Nie sądzę, aby argumenty „polecenie <spacja>” były kiedykolwiek standardowym formatem w cmd (lub jednym z jego poprzedników); rozważ na przykład dir/apodobną składnię VMS.
grawity
6
cd jest bardzo wyjątkowy. Możesz pisać cd c:\program filesbez cudzysłowów i nadal działa
phuclv
20
Tutaj jest bardzo zabawny artykuł, który wyjaśnia dziwactwa logiki powłoki Windows, a co może spowodować okaleczenie: thedailywtf.com/articles/The-Core-Launcher
VSZ
3
Dlaczego cd..działa Ponieważ Microsoft miał problem z jawnym uruchomieniem go. cdto polecenie wbudowane w interpreter poleceń systemu Windows, a Microsoft może zmusić ich interpretera do zrobienia tego, co chce. (Jako kolejny przykład cdnie trzeba też cytować katalogów ze spacjami w nazwie).
jamesdlin,

Odpowiedzi:

106

Jak zauważają niektóre inne odpowiedzi / komentarze, pomysł, że po poleceniu musi być spacja, jest nieprawidłowy. Dobrze znanym przykładem jest to, że po poleceniu możesz wpisać ukośnik bez potrzeby wstawiania spacji.

Istnieje jednak inne zachowanie, które jest nieco mniej zrozumiałe i pozwala „ cd..” o które pytasz. Takie zachowanie pozwala również na działanie „ cd\”.

Opisane zachowanie jest spójne dla wszystkich poleceń wewnętrznych interpretera wiersza poleceń. Jeśli masz określone symbole, w tym kropkę, ukośnik lub ukośnik odwrotny, sprawdzane są wcześniejsze znaki, aby sprawdzić, czy są one poleceniem wewnętrznym powłoki „interpretera wiersza poleceń” (CMD.EXE lub jej poprzednika COMMAND.COM ).

Można to zrobić przed sprawdzeniem, czy słowo może odnosić się do pliku lub podkatalogu. Dotyczy to cdpolecenia. Tragicznie, gdy tworzyłem próbkę, stwierdziłem, że tak się nie dzieje z copypoleceniem, więc wyniki są niespójne: niekoniecznie są takie same dla wszystkich poleceń wewnętrznych. Nie kontynuować przeszukiwanie również Porównaj (dużo) Inne komendy wiersz deli dirtak po prostu sugerują, że jest niezwykle ostrożny, jeśli starają się polegać na tym, co dzieje się bez przestrzeni.

Teraz pytanie dotyczy także polecenia echa : To niezwykły wyjątek, ponieważ moim zdaniem echo.jest dość dobrze znany ekspertom DOS. To prawdopodobnie zostało udokumentowane. Zachowanie, przynajmniej w CMD Win7 , jest takie, że jeśli polecenie zaczyna się od „ echo.”, to pierwszy okres jest ignorowany. Tak więc „ echo..hi” zamienia się w wynik „ .hi”. Powodem tego jest to, że echo.można użyć „ ” do wydrukowania pustej linii. W przeciwieństwie do Unixa możesz to zrobić po prostu uruchamiając polecenie „ echo” samodzielnie. Jednak w systemie DOS samo uruchomienie polecenia „ echo” spowoduje wyświetlenie bieżącego ustawienia „ echa ”. Podobnie DOS traktuje „ Echo *Off*” i „Echo *On*„jako specjalne wartości, które zmieniają bieżące ustawienie echa. Jeśli rzeczywiście chcesz wydrukować słowo„ Off”, to„ Echo.Off”załatwia sprawę (przynajmniej w przypadku wystarczająco najnowszych wersji interpretera wiersza poleceń CMD Microsoftu .)

Tak więc przynajmniej echopolecenie ma częściowo uzasadnione wytłumaczenie. Jeśli chodzi o pozostałe polecenia, myślałem, że polecenia wewnętrzne mają priorytet. Jednak gdy próbowałem wykonać kilka testów, okazało się, że jest to raczej niespójne. Pokazuję to na kilku przykładach, które tutaj udokumentowałem.


Oto kilka przykładów. Użyłem wiersza polecenia z podwyższonym poziomem uprawnień, aby UAC nie niepokoił się tym, że piszę do katalogu głównego. Dokonano tego przy pomocy CMD.EXE systemu Microsoft Windows 7. Podejrzewam, że zachowania mogą być inne w przypadku innych wersji, takich jak COMMAND.COM ze starszych wersji MS-DOS lub oprogramowania wydanego przez inne firmy (COMMAND.COM DR-DOS).

(Ta odpowiedź jest już dość długa, więc nie uwzględniam poleceń, aby wyczyścić cały bałagan, który popełniłem w moim systemie plików. Jest trochę drobnego czyszczenia, ale niewiele).

Oto przykład, który dowodzi, że polecenie wewnętrzne tworzy pierwszeństwo. (Wykazuję również dość mało znaną umiejętność używania podwójnego dwukropka, aby skutecznie być komentarzem, co również działa dobrze w plikach wsadowych. Technicznie w plikach wsadowych jest przetwarzany jako etykieta, do której GOTO nie może uzyskać, i kończy się jest szybszy niż polecenie REM).

C: \ coś> md cd
C: \ coś> echo echo podkatalog >> cd \ a.bat
C: \ coś> md \ a
C: \ coś> . \ Cd \ a.bat
subdir

C: \ coś> :: To pochodzi z podkatalogu
C: \ coś> cd \ a
C: \ a> :: To zmieniło mój bieżący katalog, więc cd miał pierwszeństwo

Aktualizacja: Po dalszych eksperymentach odkryłem, że wewnętrzne polecenie cd ma pierwszeństwo przed systemem plików tylko wtedy, gdy określony katalog nie zawiera kropki. Jeśli więc masz katalog o nazwie „ a.bat ”, możesz uruchomić „ **cd\a.bat**” i plik wsadowy zostanie uruchomiony.

Ta eksploracja mniej powszechnych zachowań (ponieważ większość katalogów prawdopodobnie nie ma w nich kropek) skłoniła mnie do aktualizacji moich ustaleń. Okazuje się, że polecenie cd zachowuje się bardziej podobnie do polecenia kopiowania, niż początkowo myślałem.

Chociaż początkowo myślałem, że polecenia cd i kopiowania zachowują się inaczej, teraz zorientowałem się, że wynika to z wzorca nazw, które podawałem. Mimo to przejrzałem wcześniejsze wyniki i stwierdziłem, że moje wcześniej udokumentowane testy pomagają pokazać różnicę między tym, co dzieje się, gdy nazwa zawiera kropkę i rozszerzenie, a kiedy nie. Tak więc nadal dołączam moje starsze ustalenia poniżej (głównie niezmienione, ale z kilkoma bardzo drobnymi aktualizacjami, więc to, co mówię, jest dokładne).

Oto przykład pokazujący, że kopia z pełną ścieżką nie używa tego samego pierwszeństwa (faworyzowanie wewnętrznego polecenia) jak cd, gdy nie jest używane rozszerzenie:

C: \ coś> echo root root >> \ try.bat
C: \ coś> md copy
C: \ coś> podkatalog echo echo >> copy \ try.bat
C: \ coś> . \ Copy \ try.bat działa z podkatalog
podkatalog

C: \ coś> kopiuj \ try.bat
podkatalog

C: \ coś> :: Huh? Dlaczego to nie zastąpiło i nie uruchomiło się z katalogu głównego?
C: \ coś> :: Najwyraźniej wewnętrzne polecenie kopiowania nie miało pierwszeństwa przed sprawdzeniem podkatalogu i pełnej nazwy pliku (nawet jeśli wewnętrzne polecenie cd miało priorytet, gdy katalog nie miał rozszerzenia)
C: \ coś> ::
C: \ coś>:: Kolejny test: mogę dodać bezużyteczne kropki na końcu
C: \ coś> . \ Copy .. \ try.bat
podkatalog

C: \ coś> :: Dobra, świetnie. Ale to nie sprawdzi podkatalogu:
C: \ coś> skopiuj .. \ try.bat
        1 skopiowane pliki.

C: \ coś> :: To uruchomiło wewnętrzne polecenie kopiowania

Moje wczesne ustalenia wykazały, że wyniki te pokazują, że powłoka wiersza poleceń daje pierwszeństwo:

  • do systemu plików (zamiast wewnętrznego polecenia kopiowania ) przy określaniu odwrotnego ukośnika zaraz po nazwie wewnętrznego polecenia
  • do wewnętrznej komendy cd (zamiast systemu plików) podczas określania ukośnika odwrotnego zaraz po nazwie komendy wewnętrznej.
  • do wewnętrznego polecenia kopiowania (zamiast systemu plików) przy określaniu kropki bezpośrednio po nazwie polecenia wewnętrznego.

To wyraźnie pokazuje, że zachowanie nie jest spójne między poleceniem kopiowania (z pełną nazwą pliku wraz z rozszerzeniem) a poleceniem cd (bez rozszerzenia jako części nazwy katalogu). Podczas korzystania z ukośnika odwrotnego polecenie kopiowania (z pełnym rozszerzeniem nazwy pliku) najpierw sprawdzi system plików, ale polecenie cd nie (jeśli katalog nie zawiera rozszerzenia).

(Aktualizacja: Na początku myślałem, że niespójność była oparta na różnych zachowaniach między programami. Później odkryłem, że niespójność istniała, ale była spowodowana bardziej z podanych parametrów.)

W rzeczywistości nawet te pociski nie są do końca dokładne, chociaż zdawałem się demonstrować każdą konkretną rzecz, którą właśnie powiedziałem. Problem polega na tym, że lista punktorów nie jest wystarczająco precyzyjna, aby była całkowicie dokładna. (Pozostawiłem rzeczy nieprecyzyjne, aby te punkty punktowe można było stosunkowo łatwo porównać i stosunkowo łatwo sprawdzić).

Jednak, aby być bardziej dokładnym, pierwszy punktor powinien wskazać, że powłoka wiersza poleceń daje pierwszeństwo:

  • do systemu plików (zamiast wewnętrznego polecenia kopiowania ) podczas określania ukośnika odwrotnego, a następnie pozostałą część pełnej ścieżki, zaraz po nazwie polecenia wewnętrznego

Poniższe wykaże, dlaczego wprowadzam to rozróżnienie:

C: \ elsewhere> echo UAC wymagane dla tej linii >> \ needext
C: \ elsewhere> echo UAC wymagane dla tej linii >> \ 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 pliki skopiowane.

C: \ elsewhere> :: UAC potrzebne również w następnych wierszach
C: \ elsewhere> del \ needext
C: \ elsewhere> del \ needext.bat

(Zauważ, że ostatnie polecenie kopiowania szukało pliku o nazwie \ needext , ponieważ użyto wewnętrznego polecenia kopiowania . Plik \ needext.bat został utworzony tylko po to, aby łatwo pokazać, że nigdy nie był używany przez wiersze poleceń zawierające słowo kopiuj .)

W tym momencie ustaliłem pewną niespójność (z zachowaniem się polecenia kopiowania ), gdy używany jest ukośnik odwrotny ...

Następnie pokażę, że istnieje pewna spójność między tymi poleceniami. (Więc istnieje spójność ... um ... czasami. Możemy mieć tylko spójność, niekonsekwentnie.) Następnie pokażę, że polecenie cd zachowuje się raczej jak polecenie kopiowania, gdy używana jest kropka. Polecenie kopiowania używa polecenia wewnętrznego, podobnie jak polecenie cd .

C: \ coś> md. \ Yetmore

C: \ coś> cd. \ Yetmore

C: \ coś \ yetmore> md. \ Md
C: \ coś \ yetmore> katalog echa echo subdir >> md \ test.bat
C: \ coś \ yetmore> . \ md. \ test
podkatalog

C: \ coś \ yetmore> md. \ test

C: \ coś \ yetmore> md. \ test Podkatalog
lub plik. \ test już istnieje.

C: \ coś \ yetmore> :: Ten błąd pokazuje, że uruchomiliśmy polecenie wewnętrzne.
C: \ coś \ yetmore> md .. \ test
C: \ coś \ yetmore> md. \ Cd
C: \ coś \ yetmore> skopiuj. \ Md cd
. \ Md \ test.bat Skopiowano
        1 pliki.

C: \ coś \ yetmore> . \ Cd. \ Test
podkatalog

C: \ coś \ yetmore> cd. \ Test
C: \ coś \ yetmore \ test> :: polecenie wewnętrzne działało z jedną kropką
C: \ coś \ yetmore \ test> cd ..
C: \ coś \ yetmore> . \ cd .. \ test
podkatalog

C: \ coś \ yetmore> cd .. \ test
C: \ coś \ test> :: polecenie wewnętrzne również miało priorytet, gdy dwa okresy są używany

Tak więc, podczas początkowej sesji testowej, która skupiała się głównie na komendach cd i kopiowania (z pewnym dodatkowym użyciem md i odrobiną del ), jedynym czasem, kiedy naprawdę mieliśmy system plików na pierwszym miejscu, było polecenie kopiowania , a następnie system plików miał priorytet tylko przy użyciu pełnej ścieżki.

Po kolejnej recenzji okazało się, że polecenie cd również przyznało pierwszeństwo systemowi plików podczas używania rozszerzenia. Przynajmniej oznacza to, że polecenia wewnętrzne są traktowane bardziej spójnie ze sobą. Oznacza to jednak również, że otrzymujemy różne zachowanie w zależności od nazw obiektów systemu plików (plików lub katalogów). Wygląda na to, że w zachowaniu jest wykorzystywana naprawdę, bardzo niejasna logika wewnętrzna. Dlatego liczenie na takie zachowanie w różnych systemach operacyjnych jest czymś, co prawdopodobnie uważałbym za niebezpieczne .

TOOGAM
źródło
„Opisane zachowanie jest spójne dla wszystkich poleceń wewnętrznych interpretera wiersza poleceń”. ipconfigna przykład też działa.
Jonas Köritz,
@ JonasKöritz: Nie. Możesz wstawić (do przodu) ukośnik zaraz po poleceniu „ IPConfig ” i to zadziała, np IPCONFIG/ALL. Jednak nie o tym mówiłem. „ Zachowanie, które opisujesz ” (w swoim pytaniu) to zachowanie polegające na umieszczeniu kropki bezpośrednio po nazwie polecenia. Jeśli piszę, IPConfig.pojawia się błąd związany z brakiem polecenia. Podobnie (chociaż nie jest to związane z opisywanym zachowaniem), jeśli piszę IPCONFIG\ALL, mogę uruchomić utworzony przez siebie .\IPCONFIG\ALL.BATplik niestandardowy . Więc /nie są traktowani jak .ani `\ '
TOOGAM
1
Zaakceptuję twoją odpowiedź, aby docenić pracę i badania potrzebne do jej stworzenia!
Jonas Köritz
2
@ Calchas Prosty test - spróbuj wykonać copy.exelub copy.comw cmd. Nie działa - nie jest wykonywalny.
Luaan,
1
@Luann: Jeśli chodzi o ipconfig, nie zgadzam się z twoim wnioskiem. To pytanie dotyczy tego, co wpisujesz na początku wiersza poleceń. Windows / DOS identyfikuje pliki wykonywalne według rozszerzenia nazwy pliku, więc nie można uruchomić programu o nazwie „ipconfig” bez rozszerzenia (w Windows, w przeciwieństwie do Uniksa, który na to pozwala). Jeśli chodzi o następny komentarz, nie wiem, kim jest „Calchas”. (Gdy podasz znak at, następujące są zazwyczaj pierwsze znaki użytkownika, które pojawiają się w innym miejscu strony.) Zgadzam się, uruchomienie „ copy.exe” spowoduje użycie wewnętrznego copypolecenia (i przekaże .exe). (Możesz biegać .\copy.exe)
TOOGAM
41

Zakładasz, że nazwa polecenia i jego argumenty muszą być oddzielone spacją, ale nie jest to prawdą. Dopóki wywoływanie może być jednoznacznie interpretowane, wywoływanie jest ważne.

W tym przypadku, pierwszy argument zaczyna się .i .nie może być częścią nazwy poleceń, tak cdi ..po prostu analizowany jako dwa odrębne tokeny.

Zwykle pierwszy argument zaczyna się od znaku alfabetu (np. Początku ścieżki), więc „wykrwawia się” w nazwie polecenia i powoduje błąd… ale to nie jest problem ze składnią. Jest semantyczny.

Ten sam efekt możesz zobaczyć w pracy z innymi poleceniami, w tym echo:

echo...
..

W tym przypadku, mamy tylko dwa okresy, ponieważ sama komenda ma specjalną regułę , dzięki czemu następuje:echo

echo .

lub, co za tym idzie, to:

echo.

wyświetla tylko pustą linię. To wygoda. Najwyraźniej został zaimplementowany poprzez zignorowanie wiodącego okresu w argumencie.

Hej, to jest DOS / Batch. Chcesz zdrowia psychicznego? :RE

Lekkość Wyścigi na orbicie
źródło
2
Założyłem to, ponieważ jest on unikalny dla wiersza poleceń systemu Windows, na przykład bash nie pozwoli ci tego zrobićcd..
Jonas Köritz
47
@ JonasKöritz: To zupełnie inny program na zupełnie innym systemie operacyjnym. Mój rower też nie pozwala cd..:)
Lekkość ściga się na orbicie
15
@ JonasKöritz:alias cd..='cd ..'
mouviciel
5
@LightnessRacesinOrbit: Początkowo był to skrót do filtrowania .i ..który pojawia się jako katalogi w każdym innym katalogu i, o ile wiem, nigdy nie miał na celu złapania więcej. Właściwie uważam, że ukryty model jako atrybut pliku jest czystszym projektem niż to, że domyślnie wynika z nazwy pliku.
Joey,
4
@joey - Myślę, że bardziej istotnym punktem nie jest to, że podejście DOS było prostsze, ale to, że DOS nie zezwalał .na nazwy plików , co oznaczało, że nie mógł być częścią nazwy polecenia, dlatego musiał być częścią argumentu . Nawet jeśli DOS podzielił polecenie na argumenty, tak jak robią to powłoki uniksowe, nadal umieściłby znak .po poleceniu w pierwszym argumencie, ponieważ nie ma sensu wstawiać niepoprawnego znaku w nazwie polecenia.
Jules
19

cd..Komenda jest poprawna i została zdefiniowana jak w pierwotnym interpreter poleceń command.com, które później nazwano cmd.exe.

Interpretator poleceń wie, jak przetwarzać cd.., ponieważ .jest to znak specjalny, podobnie jak \.

Overmind
źródło
8
Myślę, że głównym problemem jest to, że polecenie nie może być „niepoprawne składniowo”, ponieważ składnia nie jest formalnie nigdzie określona , więc jeśli podstawowa implementacja (cmd.exe i / lub MS-DOS) ją akceptuje, to musi być poprawna.
grawity
3
Ponadto CD nie jest programem, ale wewnętrznym poleceniem. Podobnie jak Echo, które jest również wewnętrznym poleceniem, nie musi mieć miejsca na jego działanie. echo.działa równie dobrze, co spowoduje wydrukowanie pustej linii.
LPChip
2
@Overmind echoe też nie będzie działać, więc jest tak samo z cd, echo, md itp.
LPChip
2
@ JonasKöritz, .nie jest upuszczany, ale dodaje się tylko spację. md.testi md .testoba tworzą katalog .test. Wpisując cd.testi cd .testprzejdzie do katalogu .test.
daniel.neumann
6
@ JonasKöritz: Ponieważ składnia nigdy nie była argumentami przestrzeni poleceń.
Wyścigi lekkości na orbicie
11

Jest to hack kompatybilności wstecznej.

Interpretator wiersza poleceń został zaprojektowany tak, aby był kompatybilny wstecz z poleceniami oryginalnego interpretera poleceń MSDOS, który został zaprojektowany tak, aby był kompatybilny wstecz z interpreterem poleceń CP / M. Ani CP / M, ani MSDOS nie zezwalają na a .w nazwie pliku (było to interpretowane jako separator między dwiema częściami nazwy pliku, nazwą podstawową i rozszerzeniem). Oznaczało to, że (przynajmniej we wczesnych wersjach DOS) interpreter poleceń mógłby rozpoznać, że jeśli osiągnie „.” (lub w rzeczywistości jakikolwiek inny znak, który był niedozwolony w nazwie pliku), przekazał koniec nazwy polecenia i znalazł się w argumentach polecenia. Było to dość powszechnie stosowane zarówno w DOS, jak i CP / M - na przykład, dir/wbyło to bardzo popularne polecenie, równoważne dir /wznaczeniu wyświetlania listy plików w formacie poziomym.

Dzisiaj, '.' może pojawić się w nazwach plików. Powoduje to pewne komplikacje w przetwarzaniu poleceń, ale powłoka nadal identyfikuje plik, .który nie jest częścią dokładnej nazwy pliku, jako początek argumentów. Jest to konieczne głównie dlatego, że miliony użytkowników przyzwyczaiły się do pisania cd..lub mają dużą liczbę plików wsadowych zawierających tę echo.lub dowolną liczbę innych podobnych poleceń.

Jules
źródło