Tại sao cd không phải là một chương trình?


129

Tôi đã luôn tự hỏi tại sao cdkhông phải là một chương trình, nhưng không bao giờ tìm được câu trả lời.

Bất cứ ai cũng biết tại sao đây là trường hợp?



1
Tôi nhớ đã đọc (tôi không thể tìm thấy ở đâu) rằng cdlệnh unix ban đầu là một chương trình riêng biệt. Vỏ xử lý nó đặc biệt ở chỗ nó không fork, chỉ exec. Và khi cdđược thực hiện, nó sẽ thực thi sh. Tôi không biết nếu đây là một câu chuyện có thật.
camh

Điều gì sẽ là điểm? Nếu nó sẽ thêm xử lý đặc biệt, nó cũng có thể chỉ cần gọi tòa nhà chdir. nguồn: v1 v5 v7 (phiên bản đầu tiên có vỏ Bourne)
Mikel

2
@camh, đó là một câu chuyện có thật. Tôi cũng đã đọc điều đó trong một bài báo được viết bởi Dennis M. Ritchie, về sự phát triển của hệ thống chia sẻ thời gian Unix, Tạp chí kỹ thuật phòng thí nghiệm của AT & T Bell 63 (6), Phần 2, tháng 10 năm 1984.
jlliagre

@Mikel: Tôi đồng ý rằng nó có vẻ vô nghĩa, nhưng tôi chỉ đang chuyển tiếp một câu chuyện về cdđiều mà tôi đã đọc. Tôi đã sai rõ ràng về khía cạnh của nó, bây giờ @jlliagre đã điền vào các chi tiết.
camh

Câu trả lời:


172

Các cdlệnh làm thay đổi các "thư mục làm việc hiện tại", phải không?

"thư mục làm việc hiện tại" là một thuộc tính duy nhất cho mỗi quy trình.

Vì vậy, nếu cdlà một chương trình, nó sẽ hoạt động như thế này:

  1. cd foo
  2. các cdquá trình khởi động
  3. các cdquá trình thay đổi thư mục cho quá trình cd
  4. các cdlối ra quá trình
  5. shell của bạn vẫn có trạng thái tương tự, bao gồm cả thư mục làm việc hiện tại, nó đã làm trước khi bạn bắt đầu.

8
Năm bước của bạn là chính xác nhưng "nếu cdlà một chương trình thì nó sẽ hoạt động như thế này" nên "khi cdđược sử dụng trong triển khai chương trình bên ngoài, nó hoạt động như thế này".
jlliagre

1
Không phải là một lập trình viên hệ thống, cũng không thực sự có kiến ​​thức sâu sắc về các hoạt động tương tác với shell, tôi đã mong đợi shell sẽ hiển thị thư mục làm việc hiện tại của nó và cd là một chương trình truy cập và thay đổi thuộc tính đó. Hiểu, sau khi xem câu trả lời này, đó có lẽ là tối ưu cho cách nó thực sự hoạt động vì nhiều lý do.
Jason

108

cdngoài việc là một phần mềm dựng sẵn, thực sự cũng là một chương trình trên các HĐH tuân thủ POSIX. Họ phải cung cấp các tệp thực thi độc lập cho các tiện ích thông thường, như cd. Đây là ví dụ trường hợp với Solaris , AIX , HP-UX và OS X .

Rõ ràng, một dựng sẵn cdlà vẫn bắt buộc như thực hiện bên ngoài của nó không thay đổi thư mục shell hiện hành. Tuy nhiên, sau này vẫn có thể hữu ích. Dưới đây là một ví dụ cho thấy POSIX hình dung cách cdsử dụng lệnh này :

find . -type d -exec cd {} \;

Trên hệ thống POSIX, oneliner này sẽ báo cáo thông báo lỗi cho tất cả các thư mục bạn không được phép cdvào. Trên hầu hết các bản phân phối Gnu / Linux, mặc dù vậy, nó không thành công với thông báo lỗi đó:

find: `cd': No such file or directory

Và đây là câu trả lời cho câu hỏi của bạn, " Tại sao cd không phải là một chương trình? " Bởi một trong những đồng tác giả Unix gốc. Trong một triển khai Unix rất sớm, cd(đánh vần chdirvào thời điểm đó) là một chương trình bên ngoài. Nó chỉ dừng hoạt động bất ngờ sau khi forkđược thực hiện lần đầu tiên.

Trích dẫn Dennis Ritchie :

Giữa sự hân hoan của chúng tôi, người ta phát hiện ra rằng lệnh chdir (thay đổi thư mục hiện tại) đã ngừng hoạt động. Có nhiều cách đọc mã và nội tâm lo lắng về việc bổ sung fork có thể phá vỡ cuộc gọi chdir như thế nào. Cuối cùng, sự thật đã sáng tỏ: trong hệ thống cũ, chdir là một mệnh lệnh thông thường; nó đã điều chỉnh thư mục hiện tại của quá trình (duy nhất) được gắn vào thiết bị đầu cuối. Trong hệ thống mới, lệnh chdir đã thay đổi chính xác thư mục hiện tại của quy trình được tạo để thực thi nó, nhưng quá trình này đã nhanh chóng chấm dứt và không có tác dụng gì đối với trình bao mẹ của nó! Nó là cần thiết để làm cho chdir trở thành một lệnh đặc biệt, được thực thi bên trong shell. Nó chỉ ra rằng một số chức năng giống như lệnh có cùng thuộc tính, ví dụ đăng nhập.

Nguồn: Dennis M. Ritchie, Hồi Sự phát triển của hệ thống chia sẻ thời gian Unix , Tạp chí kỹ thuật phòng thí nghiệm của AT & T Bell 63 (6), Phần 2, tháng 10 năm 1984, tr.1577

Trang hướng dẫn sử dụng chdir phiên bản Unix 1 (tháng 3 năm 1971) :

Vì một quy trình mới được tạo để thực thi mỗi lệnh, chdir sẽ không hiệu quả nếu nó được viết như một lệnh bình thường. Do đó, nó được công nhận và thực hiện bởi Shell.


10
... Vì vậy, rõ ràng, POSIX yêu cầu rằng sẽ có một cdtệp thực thi độc lập , nhưng nó sẽ không làm gì cả (ngoại trừ có thể phát ra các thông báo lỗi nếu được gọi với các đối số sai). Kỳ dị.
Ilmari Karonen

4
Ồ, nếu nó là sự thật, đó sẽ không phải là điều ngu ngốc nhất trong POSIX.
Kaz

5
Các trang cd POSIX cũng nói "Kể từ cd ảnh hưởng đến môi trường thực thi shell hiện tại, nó luôn luôn được cung cấp như một vỏ thường xuyên built-in.".
Mikel

6
@Kaz, chúng không phải là những thứ hoàn toàn khác nhau. Họ làm điều tương tự nhưng chỉ có phần dựng sẵn ảnh hưởng đến lớp vỏ hiện tại.
jlliagre

13
@Kaz: Xin đừng gọi tôi là ngớ ngẩn trong khi tôi chỉ báo cáo một sự thật. Bạn có thể đồng ý hoặc không đồng ý với POSIX nhưng đừng bắn sứ giả.
jlliagre

47

Từ phần giới thiệu Bash ( Vỏ là gì? ):

Shell cũng cung cấp một tập hợp nhỏ các lệnh tích hợp (dựng sẵn) thực hiện chức năng không thể hoặc bất tiện để có được thông qua các tiện ích riêng biệt. Ví dụ, cd, break, continue, và exec) không thể được thực hiện bên ngoài của vỏ vì họ trực tiếp thao tác các vỏ thân. Các history, getopts, kill, hoặc pwddựng sẵn, trong số những người khác, có thể được thực hiện trong các tiện ích riêng biệt, nhưng họ là thuận tiện hơn để sử dụng lệnh như dựng sẵn. Tất cả các nội dung shell được mô tả trong các phần tiếp theo.


29

Cho ngày Cá tháng Tư năm nay, tôi đã viết một phiên bản độc lậpcd .

Không ai có được trò đùa. Thở dài.

Bất cứ ai không chắc chắn rằng cdphải được tích hợp vào shell nên tải xuống, xây dựng và thử nó.

Đọc trang người đàn ông của nó, quá. :)


Mã thực sự hữu ích! :-)
dschulz

6
Thật tốt khi thấy ai đó làm việc để làm cho Gnu / Linux tuân thủ POSIX hơn. Việc triển khai của bạn không chỉ là một trò đùa hay mà thực sự còn thiếu một chút gì đó từ các bản phân phối Linux ...
jlliagre

8
Tôi nghĩ rằng tôi sẽ thử lại vào năm tới, trích dẫn vấn đề POSIX. ;)
Warren Young

6 năm sau: Vâng, phải không?
Peter A. Schneider

@ PeterA.Schneider: Tôi nghĩ rằng rõ ràng là tôi đang nói đùa, vì vậy để rõ ràng, không, tôi thực sự sẽ không tốn nhiều công sức để cố gắng đưa nó vào các dự án OS và OS như Cygwin hiện tại thiếu /bin/cd. Nếu bạn muốn lấy mã của tôi và thực hiện nhiệm vụ cá nhân của riêng bạn, bạn có thể làm như vậy.
Warren Young

4

Các cdlệnh trong shell không thể là một quá trình riêng biệt bởi vì trong Unix không có cơ chế để thay đổi thư mục làm việc hiện tại của một quá trình khác nhau (thậm chí không phải là quá trình cha mẹ).

Nếu cdlà một quá trình khác thì nó sẽ phải thay đổi thư mục làm việc hiện tại của cha mẹ (shell) không thể có trong Unix. Thay vào đó cdlà một lệnh được xây dựng đặc biệt. Shell gọi các hàm như chdir()fchdir() thay đổi thư mục làm việc hiện tại của chính nó.

Lưu ý: kernel lưu số inode của thư mục làm việc hiện tại cho mọi tiến trình. Quá trình con kế thừa nó cwdtừ cha mẹ của nó.


0

cd là một lệnh tích hợp shell. Dễ dàng như vậy. Người đàn ông cd nói lên tất cả. lệnh cd thay đổi thư mục làm việc cho tất cả các trình thông dịch và (trong môi trường luồng) tất cả các luồng.


Bởi vì shell là môi trường quan tâm đến các thư mục làm việc hiện tại của bạn ($ PDW ...) hoặc cdable_vars. Nội dung này cuối cùng là cách mà tất cả các lệnh hiển thị của người dùng sẽ thay đổi thư mục làm việc hiện tại. Bạn có thể kiểm tra theo cách đó: biên dịch bash mà không cần cd.c và cố gắng viết tập lệnh cd của riêng bạn, để kiểm tra tất cả các cdable_vars môi trường. Câu hỏi này cũng nhiều hơn một nhà phát triển liên quan. Tôi cá là họ có thể trả lời bạn câu hỏi này chi tiết hơn.

2
Có một lý do kỹ thuật rất tốt cdđược tích hợp sẵn. Tôi sẽ đề nghị bạn đọc các câu trả lời được xếp hạng cao nhất và xem xét cách trả lời của bạn có thể được cải thiện.
Thorbjørn Ravn Andersen

Câu trả lời được xếp hạng cao nhất là điều tồi tệ nhất tôi từng đọc! Nhưng hả? Tôi là ai!

3
Nhưng nó trả lời câu hỏi tại sao .
Thorbjørn Ravn Andersen

-1

Tôi nghĩ một điều còn thiếu trong câu trả lời của mọi người là thư mục hiện tại là một biến môi trường mà mỗi chương trình có thể thay đổi. Nếu bạn sử dụng lệnh 'export' để xem danh sách các biến môi trường hiện tại của mình, bạn sẽ có:

declare -x PWD="/home/erfan"

trong kết quả của bạn. Do đó, bằng lệnh 'cd', chúng tôi chỉ muốn sửa đổi biến nội bộ này. Tôi nghĩ rằng nếu chúng ta cố gắng, tất nhiên chúng ta có thể điều khiển biến PWD của bất kỳ pty nào trong shell. Như:

cder    #change current PTY $PWD variable

Nhưng tôi nghĩ không cần trong trường hợp bình thường. Nói cách khác, chúng tôi nhận trợ giúp từ bash (hoặc bất kỳ shell nào) để sửa đổi biến nội bộ của nó được xác định.


3
Mặc dù đúng là các vỏ Bourne phơi bày thư mục làm việc hiện tại (CWD) là $ PWD, nhưng đó không phải là vị trí lưu trữ chính; vị trí thực tế nằm trong cấu trúc mỗi quá trình của kernel. Do đó, không đúng khi nói rằng CWD "là một biến môi trường." Nếu nó làm việc theo cách bạn gợi ý, đây C hai lót sẽ in các ..con đường, không phải là con đường bạn bắt đầu nó từ: #include <stdlib.h> int main(void) { chdir(".."); puts(getenv("PWD")); }(C vỏ phơi bày CWD tính theo% cwd thay vào đó, bằng cách này.)
Warren Young

cho phép thêm một số dòng khác vào ứng dụng của bạn. #include <stdlib.h> int main (void) {chdir (".."); đặt (getenv ("NKT")); setenv (P "NKT", "/", 1); đặt (getenv ("NKT")); } Chúng ta sẽ có kết quả gì?
Erfankam

3
Điều đó sẽ chỉ ghi đè lên giá trị của một biến, không có tác dụng phụ trên CWD. Đây là một thử nghiệm tốt hơn để chỉ ra rằng: #include <unistd.h> int main(void) { char ac[99]; setenv("PWD", "/", 1); puts(getcwd(ac, sizeof(ac))); }Nó sẽ hiển thị thư mục bạn đã khởi động chương trình từ đó chứ không phải /.
Warren Young

Tôi nghĩ rằng mọi quá trình đều có một thư mục làm việc và biến đường dẫn. Vì vậy, bạn bởi chdir chỉ cần thay đổi thuộc tính của quá trình này. Shell cũng có thuộc tính này và bằng cd, chúng tôi sửa đổi điều này.
Erfankam

4
Không, tôi đang nói với bạn rằng nó $PWDchỉ có ý nghĩa với vỏ Bourne. Nó chỉ là một cách để shell truyền đạt thứ gì đó mà nó biết đến shell script để họ không phải gọi pwdđể tìm nó. Bất kỳ chương trình độc lập tùy thuộc vào giá trị của $PWDsẽ không đáng tin cậy.
Warren Young
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.