Làm thế nào để Unix theo dõi thư mục làm việc của người dùng khi điều hướng hệ thống tệp?


29

Nói rằng tôi đăng nhập vào hệ vỏ trên hệ thống unix và bắt đầu khai thác các lệnh. Tôi ban đầu bắt đầu trong thư mục nhà của người dùng của tôi ~. Tôi có thể từ đó cdxuống thư mục Documents.

Lệnh thay đổi thư mục làm việc ở đây rất đơn giản để hiểu một cách trực giác: nút cha có một danh sách các nút con mà nó có thể truy cập và có lẽ nó sử dụng một biến thể (được tối ưu hóa) của một tìm kiếm để xác định sự tồn tại của nút con với Tên người dùng đã nhập và thư mục làm việc sau đó được "thay đổi" để khớp với điều này - sửa tôi nếu tôi sai ở đó. Thậm chí có thể đơn giản hơn khi shell chỉ đơn giản là "ngây thơ" cố gắng truy cập thư mục chính xác theo mong muốn của người dùng và khi hệ thống tệp trả về một số loại lỗi, shell sẽ hiển thị phản hồi tương ứng.

Tuy nhiên, điều tôi quan tâm là cách thức hoạt động của cùng một quy trình khi tôi điều hướng một thư mục, tức là đến cha mẹ hoặc cha mẹ của cha mẹ.

Với vị trí không xác định, có lẽ là "mù" của tôi Documents, một trong nhiều thư mục trong toàn bộ cây hệ thống tệp có tên đó, làm thế nào để Unix xác định nơi tôi nên đặt tiếp theo? Liệu nó làm cho một tài liệu tham khảo pwdvà kiểm tra đó? Nếu có, làm thế nào để pwdtheo dõi trạng thái điều hướng hiện tại?


Câu trả lời:


76

Các câu trả lời khác là quá đơn giản, mỗi phần chỉ trình bày các phần của câu chuyện và sai ở một vài điểm.

hai cách để theo dõi thư mục làm việc:

  • Đối với mọi quy trình, trong cấu trúc dữ liệu không gian nhân đại diện cho quy trình đó, nhân lưu trữ hai tham chiếu vnode đến vnodes của thư mục làm việc và thư mục gốc cho quy trình đó. Tham chiếu trước được thiết lập bởi các cuộc gọi chdir()fchdir()hệ thống, sau này bởi chroot(). Người ta có thể thấy chúng gián tiếp /proctrên các hệ điều hành Linux hoặc thông qua fstatlệnh trên FreeBSD và tương tự:

    % fstat -p $$ | đầu -n 5
    NGƯỜI DÙNG CMD PID FD MOUNT INUM MODE SZ | DV R / W
    JdeBP zsh 92648 văn bản / 24958 -r-xr-xr-x 702360 r
    JdeBP zsh 92648 ctty / dev 148 crw - w ---- pts / 4 rw
    JdeBP zsh 92648 wd / usr / home / JdeBP 4 drwxr-xr-x 124 r
    JdeBP zsh 92648 root / 4 drwxr-xr-x 35 r
    % 

    Khi độ phân giải tên đường dẫn hoạt động, nó bắt đầu ở một hoặc một trong các vnodes được tham chiếu, tùy theo đường dẫn là tương đối hay tuyệt đối. (Có một nhóm các …at()cuộc gọi hệ thống cho phép bắt đầu phân giải tên đường dẫn tại vnode được tham chiếu bởi một bộ mô tả tệp mở (thư mục) dưới dạng tùy chọn thứ ba.)

    Trong microkernel Unices cấu trúc dữ liệu nằm trong không gian ứng dụng, nhưng nguyên tắc giữ các tham chiếu mở đến các thư mục này vẫn giữ nguyên.

  • Bên trong, trong các shell như Z, Korn, Bourne Again, C và Almquist, shell cũng theo dõi thư mục làm việc bằng cách sử dụng thao tác chuỗi của biến chuỗi bên trong. Nó làm điều này bất cứ khi nào nó có lý do để gọi chdir().

    Nếu một thay đổi thành một tên đường dẫn tương đối, nó sẽ thao tác chuỗi để nối thêm tên đó. Nếu một thay đổi thành một tên đường dẫn tuyệt đối, nó sẽ thay thế chuỗi bằng tên mới. Trong cả hai trường hợp, nó điều chỉnh chuỗi để loại bỏ ...các thành phần và theo đuổi các liên kết tượng trưng thay thế chúng bằng các tên được liên kết với chúng. ( Ví dụ, đây là mã Z shell cho điều đó .)

    Tên trong biến chuỗi bên trong được theo dõi bởi biến shell có tên PWD(hoặc cwdtrong shell C). Điều này thường được xuất dưới dạng một biến môi trường (được đặt tên PWD) cho các chương trình được sinh ra bởi trình bao.

Hai phương pháp theo dõi sự vật này được tiết lộ bởi -P-Lcác tùy chọn cho các lệnh tích hợp cdpwdshell, và bởi sự khác biệt giữa các pwdlệnh tích hợp của shell và cả /bin/pwdlệnh và pwdlệnh tích hợp của những thứ như (giữa các lệnh khác) VIM và NeoVIM.

% mkdir a; ln -sab 
% (cd b; pwd; / bin / pwd; printenv PWD)
/ usr / nhà / JdeBP / b
/ usr / nhà / JdeBP / a
/ usr / nhà / JdeBP / b
% (cd b; pwd -P; / bin / pwd -P)
/ usr / nhà / JdeBP / a
/ usr / nhà / JdeBP / a
% (cd b; pwd -L; / bin / pwd -L)
/ usr / nhà / JdeBP / b
/ usr / nhà / JdeBP / b
% (cd -P b; pwd; / bin / pwd; printenv PWD)
/ usr / nhà / JdeBP / a
/ usr / nhà / JdeBP / a
/ usr / nhà / JdeBP / a
% (cd b; PWD = / xin chào / có / bin / pwd -L)
/ usr / nhà / JdeBP / a
% 

Như bạn có thể thấy: có được thư mục làm việc "logic" là vấn đề xem xét PWDbiến shell (hoặc biến môi trường nếu không phải là chương trình shell); trong khi đó có được thư mục làm việc "vật lý" là vấn đề gọi getcwd()hàm thư viện.

Hoạt động của /bin/pwdchương trình khi -Ltùy chọn được sử dụng là hơi tinh tế. Nó không thể tin tưởng vào giá trị của PWDbiến môi trường mà nó được thừa hưởng. Rốt cuộc, nó không cần phải được gọi bởi shell và các chương trình can thiệp có thể không thực hiện cơ chế của shell để PWDbiến biến môi trường luôn theo dõi tên của thư mục làm việc. Hoặc ai đó có thể làm những gì tôi đã làm chỉ ở đó.

Vì vậy, những gì nó làm là (như tiêu chuẩn POSIX nói) kiểm tra xem tên được đưa ra có PWDmang lại điều tương tự như tên ., như có thể thấy với dấu vết cuộc gọi hệ thống:

% ln -sac 
% (cd b; truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / home / JdeBP / b", { mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0) 
stat (".", {mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0)
/ usr / nhà / JdeBP / b
% (cd b; PWD = / usr / local / etc truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / local / etc" , {mode = drwxr-xr-x, inode = 14835, size = 158, blksize = 10240}) = 0 (0x0) 
stat (".", {mode = drwxr-xr-x, inode = 120932, size = 2 , blksize = 131072}) = 0 (0x0)
__getcwd ("/ usr / nhà / JdeBP / a", 1024) = 0 (0x0)
/ usr / nhà / JdeBP / a
% (cd b; PWD = / hello / there truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ hello / there", 0x7fffffffe730) ERR # 2 'Không có tệp hoặc thư mục như vậy' 
__getcwd ("/ usr / home / JdeBP / a", 1024) = 0 (0x0)
/ usr / nhà / JdeBP / a
% (cd b; PWD = / usr / home / JdeBP / c truss / bin / pwd -L 3> & 1 1> & 2 2> & 3 | grep -E '^ stat | __getcwd') 
stat ("/ usr / home / JdeBP / c ", {mode = drwxr-xr-x, inode = 120932, size = 2, blksize = 131072}) = 0 (0x0) 
stat (". ", {Mode = drwxr-xr-x, inode = 120932 , kích thước = 2, blksize = 131072}) = 0 (0x0)
/ usr / nhà / JdeBP / c
%

Như bạn có thể thấy: nó chỉ gọi getcwd()nếu phát hiện sự không phù hợp; và nó có thể bị đánh lừa bằng cách đặt PWDthành một chuỗi thực sự đặt tên cho cùng một thư mục, nhưng theo một tuyến khác.

Các getcwd()chức năng thư viện là một chủ đề theo đúng nghĩa của nó. Nhưng để trang trí:

  • Ban đầu nó hoàn toàn là một chức năng của thư viện, nó đã xây dựng một tên đường dẫn từ thư mục làm việc trở lại thư mục gốc bằng cách liên tục cố gắng tìm kiếm thư mục làm việc trong ..thư mục. Nó dừng lại khi nó đạt đến một vòng lặp ..giống như thư mục làm việc của nó hoặc khi có lỗi khi cố gắng mở tiếp theo ... Đây sẽ là rất nhiều cuộc gọi hệ thống dưới vỏ bọc.
  • Ngày nay tình hình phức tạp hơn một chút. Ví dụ, trên FreeBSD (điều này cũng đúng với các hệ điều hành khác), đó một cuộc gọi hệ thống thực sự, như bạn có thể thấy trong dấu vết cuộc gọi hệ thống được đưa ra trước đó. Tất cả các giao dịch từ thư mục làm việc vnode cho đến gốc được thực hiện trong một cuộc gọi hệ thống duy nhất, lợi dụng những thứ như truy cập trực tiếp của mã chế độ kernel vào bộ đệm mục nhập thư mục để thực hiện tra cứu thành phần tên đường dẫn hiệu quả hơn nhiều.

    Tuy nhiên, lưu ý rằng ngay cả trên FreeBSD và các hệ điều hành khác đó, kernel không theo dõi thư mục làm việc bằng một chuỗi.

Điều hướng đến ..một lần nữa là một chủ đề theo đúng nghĩa của nó. Một kiểu trang trí khác: Mặc dù các thư mục theo quy ước (mặc dù đã được ám chỉ, nhưng điều này là không bắt buộc) có chứa một thực tế ..trong cấu trúc dữ liệu thư mục trên đĩa, kernel theo dõi thư mục mẹ của mỗi thư mục vnode và do đó có thể điều hướng đến ..vnode của bất kỳ thư mục làm việc. Điều này hơi phức tạp bởi các điểm gắn kết và cơ chế gốc đã thay đổi, nằm ngoài phạm vi của câu trả lời này.

Qua một bên

Windows NT trong thực tế làm một điều tương tự. Có một thư mục làm việc cho mỗi tiến trình, được đặt bởi lệnh SetCurrentDirectory()gọi API và được theo dõi trên mỗi tiến trình bởi kernel thông qua một tệp xử lý tệp mở (bên trong) đến thư mục đó; và có một tập hợp các biến môi trường mà các chương trình Win32 (không chỉ là trình thông dịch lệnh, mà tất cả các chương trình Win32) sử dụng để theo dõi tên của nhiều thư mục làm việc (một trên mỗi ổ đĩa), thêm vào hoặc ghi đè chúng bất cứ khi nào chúng thay đổi thư mục.

Thông thường, không giống như các hệ điều hành Unix và Linux, các chương trình Win32 không hiển thị các biến môi trường này cho người dùng. Tuy nhiên, đôi khi người ta có thể thấy chúng trong các hệ thống con giống như Unix chạy trên Windows NT, cũng như bằng cách sử dụng các lệnh của trình thông dịch SETlệnh theo một cách cụ thể.

đọc thêm


1
Điều này là nhiều hơn tôi mong đợi. Cảm ơn bạn, và cảm ơn thêm cho việc đọc thêm!
ReactingToAngularVues

doc.cat-v.org/plan_9/4th_edition/ con / vesnames nói về một số vấn đề ..trong bối cảnh của Plan9,
icarus

@JdeBP: Có lẽ tôi đang thiếu một cái gì đó. Bạn nói, trong nội bộ, trong phạm vi, bash, tầm và khóa, shell cũng theo dõi thư mục làm việc bằng cách sử dụng thao tác chuỗi của một biến chuỗi bên trong. Re, nó điều chỉnh chuỗi để loại bỏ ...các thành phần và đuổi theo các liên kết tượng trưng thay thế chúng bằng các tên được liên kết với chúng. Tên của biến trong chuỗi chuỗi bên trong được theo dõi bởi một biến shell có tên là Tầm khắc PWD(nhấn mạnh thêm). Tiết (Cont'd)
G-Man nói 'Tái lập lại Monica'

(Tiếp theo) Nhưng ví dụ của bạn hiển thị PWD= …/bsau một cd blệnh, mặc dù đó blà một liên kết tượng trưng đến a- vì vậy, shell không đuổi theo các a -> bliên kết. Bạn đã nói sai, hay tôi đã đọc sai?
G-Man nói 'Phục hồi Monica'

Tôi chỉ đơn giản là lướt qua một điểm bên, và chỉ cho bạn mã để biết chi tiết. Xem hướng dẫn sử dụng của nhiều loại vỏ khác nhau để biết khi nào và cách chúng quyết định theo đuổi các liên kết tượng trưng hay không. Shell Z gọi một cách cẩn thận tùy chọn shell của nó là một phần của công thức quyết định , CHASE_LINKS.
JdeBP

1

Nhân không theo dõi tên thư mục hoặc tệp; một tập tin hoặc thư mục được thể hiện trong kernel bằng cặp inode / thiết bị. Các cuộc gọi hệ thống như chdir(), open()v.v. lấy một đường dẫn làm tham số, có thể là tuyệt đối (ví dụ /etc/passwd) hoặc liên quan đến thư mục hiện tại (ví dụ : Documents, ..). Khi một quá trình thực thi chdir("Documents"), một tra cứu được thực hiện Documentstrong thư mục làm việc hiện tại và thư mục làm việc của quy trình được cập nhật để tham khảo thư mục này. Từ quan điểm của kernel, không có gì đặc biệt trong tên "..", đó chỉ là một quy ước trong hệ thống tệp ..đề cập đến thư mục mẹ.

Các getcwd()chức năng không phải là một cuộc gọi hệ thống, nhưng một chức năng thư viện mà phải làm việc theo cách của mình lên vào thư mục gốc, ghi tên của các thành phần đường dẫn trên đường đi.


0

Thật thú vị, theo truyền thống cd ..là đơn giản hơn nhiều pwd. Các thư mục có tên ..được đặt rõ ràng vào hệ thống tập tin. Hệ thống theo dõi thiết bị / inode của thư mục hiện tại, do đó cd .., chính xác hơn là cuộc gọi hệ thống chdir("..")chỉ cần tìm kiếm tên ".." trong tệp thuộc về inode của thư mục hiện tại và thay đổi thiết bị / inode của thư mục hiện tại thành giá trị tìm thấy ở đó.

pwd(chính xác hơn /bin/pwd) theo ..các liên kết liên tiếp và đọc các thư mục tương ứng cho đến khi tìm thấy nút nguồn đến từ đó, tập hợp danh sách các tên đó ngược lại cho đến khi đến thư mục gốc (đáng chú ý là không chứa ..mục nhập).

Bây giờ đây là hành vi cơ bản cấp thấp ban đầu. Các lệnh shell thực tế pwdthay vì dựa vào một loạt các kỹ thuật lưu trữ tên đường dẫn hiện tại. Nhưng cốt lõi, nó chỉ là inode thực sự được biết đến. Điều đó ngụ ý rằng một khi các liên kết tượng trưng được sử dụng để điều hướng các thư mục, các khái niệm tên thư mục công việc hiện tại của shell hiện tại và của hệ thống /bin/pwdcó thể phân kỳ.

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.