Tại sao, cd cd .. .. hoạt động trong dòng lệnh Windows?


86

Khi gõ cd..mà không có khoảng trắng giữa cd..dấu nhắc lệnh Windows sẽ vui vẻ chuyển sang thư mục mẹ. Có một lời giải thích cho hành vi này? Lệnh không theo định dạng chuẩn củacommand<space>arguments

Làm việc nhưng không nên?

Ngoài ra, tại sao điều này không tạo ra kết quả nhất quán?

tiếng vang ..


24
Tiền đề của câu hỏi của bạn dường như bị phá vỡ. Bạn có thể cung cấp bất kỳ bằng chứng nào cho tuyên bố của bạn rằng điều này về mặt cú pháp không chính xác?
Các cuộc đua nhẹ nhàng trong quỹ đạo

13
Tôi không nghĩ rằng "lệnh <space> argument" đã từng là định dạng chuẩn trong cmd (hoặc bất kỳ phần tử nào của nó); xem xét ví dụ dir/ahoặc cú pháp VMS tương tự.
grawity

6
cd rất đặc biệt Bạn có thể nhập cd c:\program filesmà không có dấu ngoặc kép và nó vẫn hoạt động
phuclv

20
Đây là một bài viết rất thú vị này giải thích những khuyết tật của logic vỏ Windows, và những gì có thể gây ra tình trạng lộn xộn nó: thedailywtf.com/articles/The-Core-Launcher
Ứng dụng iPhone

3
Tại sao cd..làm việc? Bởi vì Microsoft đã trải qua những rắc rối của việc làm cho nó hoạt động rõ ràng. cdlà một lệnh được tích hợp trong trình thông dịch lệnh của Windows và Microsoft có thể khiến trình thông dịch của họ làm bất cứ điều gì họ muốn. (Như một ví dụ khác, cdcũng không cần trích dẫn xung quanh các thư mục có khoảng trắng trong tên.)
jamesdlin

Câu trả lời:


106

Như một số câu trả lời / nhận xét khác lưu ý, ý tưởng rằng phải có khoảng trắng sau lệnh không đúng. Một ví dụ nổi tiếng là bạn có thể gõ một dấu gạch chéo về phía trước sau một lệnh, mà không cần một khoảng trắng trước.

Tuy nhiên, có một hành vi khác ít được hiểu hơn và cho phép " cd.." mà bạn đang hỏi về. Hành vi này cũng cho phép " cd\" hoạt động.

Hành vi mà bạn mô tả là phù hợp cho tất cả các lệnh bên trong trình thông dịch dòng lệnh. Nếu bạn có một số ký hiệu nhất định, bao gồm dấu chấm, dấu gạch chéo hoặc dấu gạch chéo ngược, thì các ký tự trước được kiểm tra để xem liệu chúng có phải là lệnh bên trong trình bao "trình thông dịch dòng lệnh" hay không (CMD.EXE hoặc tiền thân của nó ).

Điều này có thể được thực hiện trước khi kiểm tra xem từ có thể đề cập đến một tập tin hoặc thư mục con. Điều đó đúng với cdlệnh. Đáng thương thay, khi tạo một mẫu, tôi thấy rằng điều này không xảy ra với copylệnh, vì vậy kết quả không nhất quán: chúng không nhất thiết giống nhau với tất cả các lệnh nội bộ. Tôi đã không tiếp tục tìm kiếm để so sánh (nhiều) dòng lệnh khác deldirvì vậy tôi chỉ đề nghị cực kỳ cẩn thận nếu bạn cố gắng dựa vào những gì xảy ra mà không có khoảng trắng.

Bây giờ, câu hỏi cũng được hỏi về lệnh echo : Đây là một ngoại lệ bất thường, theo tôi nghĩ echo.là khá nổi tiếng bởi các chuyên gia DOS. Điều này có lẽ đã được ghi nhận. Hành vi, ít nhất là trong CMD của Win7 , là nếu lệnh bắt đầu bằng " echo.", thì khoảng thời gian đầu tiên bị bỏ qua. Vì vậy, " echo..hi" biến thành đầu ra của " .hi". Lý do cho điều này là để " echo." có thể được sử dụng để in một dòng trống. Ngược lại, với Unix, bạn có thể thực hiện việc này một cách đơn giản bằng cách tự chạy echolệnh "". Tuy nhiên, trong DOS, tự chạy echolệnh "" sẽ tạo ra cài đặt " echo " hiện tại . Tương tự, DOS xử lý " Echo *Off*" và "Echo *On*"là các giá trị đặc biệt thay đổi cài đặt tiếng vang hiện tại. Nếu bạn thực sự muốn in từ" Off", thì" Echo.Off"thực hiện thủ thuật (ít nhất là với các phiên bản đủ của trình thông dịch dòng lệnh CMD gần đây của Microsoft .)

Vì vậy, ít nhất echolệnh có một lời giải thích bán hợp lý. Đối với các lệnh còn lại, tôi thường nghĩ rằng các lệnh nội bộ được ưu tiên. Tuy nhiên, khi tôi cố gắng thực hiện một số thử nghiệm, tôi thấy điều đó thực sự không nhất quán. Tôi chứng minh điều này thông qua một số ví dụ mà tôi đã ghi lại ở đây.


Dưới đây là một số ví dụ. Tôi đã sử dụng một dấu nhắc lệnh nâng cao, để UAC không hiểu tôi viết vào thư mục gốc. Điều này đã được thực hiện với CMD.EXE của Microsoft Windows 7. Tôi nghi ngờ các hành vi có thể khác với các phiên bản khác, chẳng hạn như.COM.COM từ các phiên bản MS-DOS cũ hơn hoặc phần mềm được phát hành bởi các công ty khác (DR-DOS's INTERN.COM).

(Câu trả lời này đã khá dài rồi, vì vậy tôi không bao gồm các lệnh để dọn sạch tất cả mớ hỗn độn tôi đã tạo trên hệ thống tập tin của mình. Có một chút dọn dẹp, nhưng không nhiều.)

Dưới đây là một ví dụ chứng minh rằng lệnh nội bộ tạo ra quyền ưu tiên. (Tôi cũng chứng minh khả năng ít được biết đến là sử dụng dấu hai chấm để nhận xét một cách hiệu quả, cũng hoạt động tốt trong các tệp bó. Về mặt kỹ thuật, trong các tệp bó, nó được xử lý như một nhãn không thể đạt được bởi GOTO và kết thúc trở nên nhanh hơn lệnh REM.)

C: \ Something > md cd
C: \ Something > echo echo subir >> cd \ a.bat
C: \ Something > md \ a
C: \ Something > . \ Cd \ a.bat
subir

C: \ Something > :: Nó chạy từ thư mục con
C: \ Something > cd \ a
C: \ a> :: Điều đó đã thay đổi thư mục hiện tại của tôi, vì vậy cd được ưu tiên

Cập nhật: Sau khi thử nghiệm thêm, tôi thấy rằng lệnh cd nội bộ chỉ được ưu tiên hơn hệ thống tập tin nếu thư mục được chỉ định không bao gồm một khoảng thời gian. Vì vậy, nếu bạn có một thư mục có tên " a.bat ", thì bạn có thể chạy " **cd\a.bat**" và tệp bó sẽ chạy.

Việc khám phá hành vi ít phổ biến này (vì hầu hết các thư mục có thể không có thời gian trong đó) khiến tôi phải cập nhật những phát hiện của mình. Hóa ra lệnh cd thực sự hoạt động giống với lệnh sao chép hơn tôi nghĩ ban đầu.

Mặc dù ban đầu tôi nghĩ rằng các lệnh cdcopy đang hoạt động khác nhau, nhưng bây giờ tôi đã hiểu ra rằng đó là do mô hình của các tên tôi đang cung cấp. Tuy nhiên, tôi đã xem xét các kết quả trước đó của mình và xác định rằng các thử nghiệm được ghi lại trước đó của tôi giúp thể hiện một số khác biệt giữa những gì xảy ra khi một tên bao gồm một khoảng thời gian và một phần mở rộng và khi nó không. Vì vậy, tôi vẫn bao gồm những phát hiện cũ hơn của tôi bên dưới (hầu như không thay đổi, nhưng với một số cập nhật rất nhỏ nên những gì tôi nói là chính xác).

Dưới đây là một ví dụ minh họa bản sao , với một đường dẫn đầy đủ, không sử dụng cùng mức ưu tiên (ưu tiên lệnh nội bộ) như cd khi không sử dụng tiện ích mở rộng:

C: \ Something > echo echo root >> \ try.bat
C: \ Something > md copy
C: \ Something > echo echo thư mục con >> copy \ try.bat
C: \ Something > . \ Copy \ try.bat chạy từ thư mục con thư mục
con

C: \ Something > copy \ try.bat
thư mục con

C: \ Something > :: Huh? Tại sao không ghi đè và chạy từ gốc?
C: \ Something> :: Rõ ràng, lệnh sao chép nội bộ không được ưu tiên kiểm tra thư mục con và tên tệp đầy đủ (mặc dù lệnh cd nội bộ đã được ưu tiên, khi thư mục không có phần mở rộng)
C: \ Something> ::
C: \ gì đó>:: Một thử nghiệm khác: Tôi có thể thêm các khoảng thời gian vô dụng vào cuối
C: \ Something > . \ Copy .. \ try.bat
thư mục con

C: \ Something > :: Được rồi, tuyệt vời. Nhưng sau đó, điều này sẽ không kiểm tra thư mục con:
C: \ Something > copy .. \ try.bat
        1 tệp đã được sao chép.

C: \ Something> :: Điều đó đã chạy lệnh sao chép nội bộ

Những phát hiện ban đầu của tôi chỉ ra rằng những kết quả này chứng minh rằng trình vỏ dòng lệnh ưu tiên:

  • vào hệ thống tập tin (thay vì lệnh sao chép nội bộ ) khi chỉ định dấu gạch chéo ngược ngay sau tên của lệnh nội bộ
  • vào lệnh cd nội bộ (thay vì hệ thống tập tin) khi chỉ định dấu gạch chéo ngược ngay sau tên của lệnh nội bộ.
  • vào lệnh sao chép nội bộ (thay vì hệ thống tập tin) khi chỉ định một khoảng thời gian ngay sau tên của lệnh nội bộ.

Điều này chứng tỏ rõ ràng rằng hành vi không nhất quán giữa lệnh sao chép (với tên tệp đầy đủ bao gồm cả phần mở rộng) và lệnh cd (không có phần mở rộng như một phần của tên thư mục). Khi sử dụng dấu gạch chéo ngược, lệnh sao chép (có phần mở rộng tên tệp đầy đủ) sẽ kiểm tra hệ thống tệp trước, nhưng lệnh cd sẽ không (nếu thư mục không chứa phần mở rộng).

(Cập nhật: Ban đầu, tôi nghĩ rằng sự không nhất quán dựa trên hành vi khác nhau giữa các chương trình. Sau đó, tôi phát hiện ra rằng sự không nhất quán đã tồn tại, nhưng được gây ra nhiều hơn từ các tham số được cung cấp.)

Trên thực tế, ngay cả những gạch đầu dòng đó cũng không hoàn toàn chính xác, mặc dù tôi dường như chỉ chứng minh mọi điều cá nhân tôi vừa nói. Vấn đề là, danh sách các gạch đầu dòng đó không đủ chính xác để hoàn toàn chính xác. (Tôi đã để lại những thứ không chính xác để những điểm đạn đó có thể được so sánh tương đối dễ dàng và được kiểm tra tương đối dễ dàng.)

Tuy nhiên, để chính xác hơn, dấu đầu dòng đầu tiên phải chỉ ra rằng vỏ dòng lệnh ưu tiên:

  • đến hệ thống tập tin (thay vì lệnh sao chép nội bộ ) khi chỉ định dấu gạch chéo ngược sau đó là phần còn lại của đường dẫn đầy đủ, ngay sau tên của lệnh nội bộ

Những điều sau đây sẽ chứng minh tại sao tôi lại tạo ra sự khác biệt đó:

C: \ ở nơi khác> echo Độ cao UAC cần thiết cho dòng này >> \ Needext
C: \ ở nơi khác> echo Độ cao UAC cần thiết cho dòng này >> \ Needext.bat
C: \ ở nơi khác> md. \ Copy
C: \ ở nơi khác> echo @ Echo subdir >> copy \ needext.bat
C: \ nơi khác> . \ copy \ needext
subdir

C: \ nơi khác> sao chép \ needext.bat
subdir

C: \ nơi khác> copy \ needext
        1 file (s) sao chép.

C: \ nơi khác> :: UAC cũng cần thiết cho các dòng tiếp theo
C: \ nơi khác> del \ Needext
C: \ nơi khác> del \ Needext.bat

(Lưu ý rằng lệnh sao chép cuối cùng đã tìm tệp có tên \ Needext , vì lệnh sao chép nội bộ đã được sử dụng. Tệp \ Needext.bat chỉ được tạo để giúp dễ dàng hiển thị rằng nó không bao giờ được sử dụng bởi các dòng lệnh có chứa bản sao từ .)

Tại thời điểm này, tôi đã thiết lập một số điểm không nhất quán (với hành vi của lệnh sao chép ) khi sử dụng dấu gạch chéo ngược ...

Tiếp theo tôi sẽ chứng minh rằng có một số thống nhất giữa các lệnh này. (Vì vậy, có tính nhất quán ... ừm ... đôi khi. Chúng ta chỉ có thể có tính nhất quán, không nhất quán.) Điều tôi sẽ trình bày tiếp theo là lệnh cd hoạt động thay vì lệnh sao chép khi sử dụng một khoảng thời gian. Lệnh sao chép sử dụng lệnh nội bộ và lệnh cd cũng vậy .

C: \ Something > md. \ Yetmore

C: \ Something > cd. \ Yetmore

C: \ Something \ yetmore> md. \ Md
C: \ Something \ yetmore> echo echo subir >> md \ test.bat
C: \ Something \ yetmore> . \ md. \ test
subir

C: \ Something \ yetmore> md. \ test

C: \ Something \ yetmore> md. \ test
Một thư mục con hoặc tệp. \ test đã tồn tại.

C: \ Something \ yetmore> :: Lỗi đó cho thấy chúng tôi đã chạy lệnh nội bộ.
C: \ Something \ yetmore> md .. \ test
C: \ Something \ yetmore> md. \ Cd
C: \ Something \ yetmore> copy. \ Md cd
. \ Md \ test.bat
        1 tệp đã được sao chép.

C: \ Something \ yetmore> . \ Cd. \ Test
subir

C: \ Something \ yetmore> cd. \ Test
C: \ Something \ yetmore \ test> :: lệnh nội bộ hoạt động với một khoảng thời gian
C: \ Something \ yetmore \ test> cd ..
C: \ Something \ yetmore> . \ cd .. \ test
subir

C: \ Something \ yetmore> cd .. \ test
C: \ Something \ test> :: lệnh nội bộ cũng được ưu tiên khi hai giai đoạn đã sử dụng

Vì vậy, trong phiên kiểm tra ban đầu chủ yếu tập trung vào các lệnh sao chépcd (với một số sử dụng bổ sung của md và một chút del ), lần duy nhất chúng tôi thực sự có hệ thống tập tin ưu tiên là với lệnh sao chép , và sau đó là hệ thống tập tin chỉ được ưu tiên khi sử dụng đường dẫn đầy đủ.

Sau khi xem xét tiếp theo, tôi thấy rằng lệnh cd cũng ưu tiên hệ thống tập tin khi sử dụng tiện ích mở rộng. Ít nhất điều này có nghĩa là các lệnh nội bộ đang được xử lý phù hợp hơn với nhau một chút. Tuy nhiên, điều đó cũng có nghĩa là chúng ta có các hành vi khác nhau dựa trên tên của các đối tượng hệ thống tệp (các tệp hoặc thư mục). Điều đó có vẻ như hành vi đang sử dụng một số logic bên trong thực sự, thực sự tối nghĩa. Do đó, dựa vào hành vi này để hoạt động trên các hệ điều hành khác nhau là điều mà tôi có thể coi là không an toàn để làm.


"Hành vi mà bạn mô tả là nhất quán cho tất cả các lệnh bên trong trình thông dịch dòng lệnh." ipconfigví dụ làm việc quá
Jonas Köritz

@ JonasKöritz: Số Bạn có thể đặt một (phía trước) giảm ngay sau khi lệnh " ipconfig " và điều đó sẽ làm việc, ví dụ IPCONFIG/ALL. Tuy nhiên, đó không phải là điều tôi đang nói. " Hành vi mà bạn mô tả " (trong câu hỏi của bạn) là hành vi đặt một khoảng thời gian ngay sau tên lệnh. Nếu tôi gõ IPConfig.thì tôi gặp lỗi về một lệnh không được tìm thấy. Tương tự (mặc dù điều này không liên quan đến hành vi bạn đang mô tả), nếu tôi nhập IPCONFIG\ALLthì tôi có thể chạy một .\IPCONFIG\ALL.BATtệp tùy chỉnh mà tôi đã thực hiện. Vì vậy, /chúng ta không được đối xử như thế nào .hoặc `\`
TẤT CẢ

1
Tôi sẽ chấp nhận câu trả lời của bạn để đánh giá cao công việc và nghiên cứu cần thiết để tạo ra nó!
Jonas Köritz

2
@Calchas Thử nghiệm đơn giản - thử thực hiện copy.exehoặc copy.comtrong cmd. Nó không hoạt động - nó không phải là một thực thi.
Luaan

1
@Luann: Về ipconfig, tôi không đồng ý với kết luận của bạn. Câu hỏi này là về những gì typeed khi bắt đầu một dòng lệnh. Windows / DOS xác định các tệp thực thi bằng phần mở rộng tên tệp, do đó bạn không thể chạy chương trình có tên "ipconfig" mà không có phần mở rộng (trong Windows, không giống như Unix cho phép điều này). Về bình luận tiếp theo, tôi không biết "Calchas" là ai. (Khi bạn chỉ định một dấu hiệu, sau đây thường là các ký tự đầu tiên của người dùng xuất hiện ở nơi khác trên trang.) Tôi đồng ý, chạy " copy.exe" sẽ sử dụng copylệnh nội bộ (và vượt qua .exe). (Bạn có thể chạy .\copy.exe)
TUYỆT VỜI

41

Bạn giả định rằng một tên lệnh và các đối số của nó phải được phân tách bằng khoảng trắng, cụ thể, nhưng điều này không đúng. Miễn là lời gọi có thể được giải thích rõ ràng, thì lời gọi đó là hợp lệ.

Trong trường hợp này, đối số đầu tiên bắt đầu bằng ..không thể là một phần của tên lệnh, vì vậy cd..được phân tách đơn giản thành hai mã thông báo riêng biệt.

Thông thường, đối số đầu tiên của bạn sẽ bắt đầu bằng một ký tự chữ cái (ví dụ: bắt đầu một đường dẫn), do đó, nó sẽ "chảy" vào tên lệnh của bạn và gây ra lỗi Lỗi nhưng đó không phải là vấn đề cú pháp. Đó là một ngữ nghĩa.

Bạn có thể thấy hiệu ứng tương tự khi làm việc với các lệnh khác, bao gồm echo:

echo...
..

Trong trường hợp này, chúng tôi chỉ nhận được hai thời kỳ vì các echolệnh chính nó có một quy tắc đặc biệt , do đó như sau:

echo .

hoặc, bằng cách mở rộng, điều này:

echo.

chỉ xuất ra một dòng trống. Thật tiện lợi. Rõ ràng nó đã được thực hiện bằng cách bỏ qua một giai đoạn hàng đầu trong tranh luận.

Này, đây là DOS / Batch. Bạn muốn sự tỉnh táo? :CƯỜI MỞ MIỆNG


2
Tôi giả sử điều này bởi vì nó là duy nhất cho dòng lệnh windows, ví dụ bash sẽ không cho phép bạn làmcd..
Jonas Köritz

47
@ JonasKöritz: Đó là một chương trình hoàn toàn khác trên một hệ điều hành hoàn toàn khác. Xe đạp của tôi cũng không cho phép cd..:)
Cuộc đua nhẹ nhàng trong quỹ đạo

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

5
@LightnessRacesinOrbit: Ban đầu nó là một lối tắt để lọc ra ...xuất hiện dưới dạng các thư mục trong mọi thư mục khác và theo như tôi biết thì không bao giờ có ý định bắt nhiều hơn thế. Tôi thực sự coi tính năng ẩn được mô hình hóa như thuộc tính tệp là một thiết kế sạch hơn là nó hoàn toàn tuân theo tên tệp.
Joey

4
@joey - Tôi nghĩ rằng điểm phù hợp hơn không phải là cách tiếp cận DOS đơn giản hơn, đó là DOS không cho phép .trong tên tệp , điều đó có nghĩa là nó không thể là một phần của tên lệnh do đó phải là một phần của đối số . Ngay cả khi DOS đã chia lệnh thành các đối số như các shell Unix, thì nó vẫn đặt .lệnh sau vào đối số đầu tiên, bởi vì sẽ không có ý nghĩa gì khi đặt một ký tự không hợp lệ vào tên lệnh.
Jules

19

Các cd..lệnh là đúng và nó được định nghĩa như thế trong thông dịch lệnh ban đầu command.commà sau này được đặt tên cmd.exe.

Trình thông dịch lệnh biết cách xử lý cd.., bởi vì .là một ký tự đặc biệt, giống như \.


8
Tôi đoán vấn đề chính là lệnh không thể "sai về mặt cú pháp" vì cú pháp không được chỉ định chính thức ở bất cứ đâu , vì vậy nếu việc triển khai chính (cmd.exe và / hoặc MS-DOS) chấp nhận nó, thì nó phải chính xác.
grawity

3
Ngoài ra, CD không phải là một chương trình, mà là một lệnh nội bộ. Tương tự như Echo cũng là một lệnh nội bộ, nó không cần phải có không gian để nó hoạt động. echo.cũng hoạt động tốt, sẽ in một dòng trống.
LPChip

2
@Overmind echoe cũng không hoạt động, do đó, nó cũng tương tự với cd, echo, md, v.v.
LPChip

2
@ JonasKöritz, .không bị bỏ mà chỉ thêm một khoảng trắng . md.testmd .testcả hai tạo thư mục .test. Gõ cd.testcd .testsẽ thay đổi vào thư mục .test.
daniel.neumann

6
@ JonasKöritz: Bởi vì cú pháp chưa bao giờ là đối số không gian lệnh.
Các cuộc đua nhẹ nhàng trong quỹ đạo

11

Đó là một hack tương thích ngược.

Trình thông dịch dòng lệnh được thiết kế để tương thích ngược với các lệnh từ trình thông dịch lệnh MSDOS ban đầu, được thiết kế để tương thích ngược với trình thông dịch lệnh CP / M. Cả CP / M và MSDOS đều không cho phép một .tên tệp (nó được hiểu là một dấu tách giữa hai phần của tên tệp, tên cơ sở và phần mở rộng). Điều này có nghĩa là (ít nhất là đối với các phiên bản đầu tiên của DOS), trình thông dịch lệnh có thể xác định rằng nếu nó đạt đến '.' (hoặc thực sự là bất kỳ ký tự nào khác bất hợp pháp trong tên tệp), nó đã vượt qua phần cuối của tên lệnh và được đưa vào các đối số lệnh. Điều này được sử dụng khá phổ biến trong cả DOS và CP / M - ví dụ, dir/wlà một lệnh rất phổ biến, tương đương với dir /wý nghĩa liệt kê các tệp ở định dạng ngang.

Ngày nay, '.' có thể xuất hiện trong tên tập tin. Điều này gây ra một số phức tạp trong cách phân tích các lệnh, nhưng trình bao vẫn xác định một .phần tử không phải là một phần của tên tệp chính xác là phần đầu của các đối số. Điều này là cần thiết phần lớn bởi vì hàng triệu người dùng đã quen với việc gõ cd..hoặc có số lượng lớn các tệp bó chứa đó hoặc echo.hoặc bất kỳ số lượng các lệnh tương tự khác.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.