Tôi có thể cat /dev
, tôi có thể ls /dev
, tôi không thể less /dev
. Tại sao không cat
cho tôi cat
thư mục này nhưng không có thư mục khác?
Tôi có thể cat /dev
, tôi có thể ls /dev
, tôi không thể less /dev
. Tại sao không cat
cho tôi cat
thư mục này nhưng không có thư mục khác?
Câu trả lời:
Trong lịch sử (lên đến V7 UNIX, hoặc khoảng năm 1979), read
cuộc gọi hệ thống đã hoạt động trên cả tệp và thư mục. read
trên một thư mục sẽ trả về một cấu trúc dữ liệu đơn giản mà chương trình người dùng sẽ phân tích để có được các mục nhập thư mục. Thật vậy, ls
công cụ V7 đã làm chính xác điều này - read
trên một thư mục, phân tích cấu trúc dữ liệu kết quả, đầu ra theo định dạng danh sách có cấu trúc.
Khi các hệ thống tập tin trở nên phức tạp hơn, cấu trúc dữ liệu "đơn giản" này trở nên phức tạp hơn, đến mức một readdir
chức năng thư viện được thêm vào để giúp các chương trình phân tích đầu ra của read(directory)
. Các hệ thống và hệ thống tập tin khác nhau có thể có các định dạng trên đĩa khác nhau, điều này đang trở nên phức tạp.
Khi Sun giới thiệu Hệ thống tệp mạng (NFS), họ muốn trừu tượng hóa hoàn toàn cấu trúc thư mục trên đĩa. read(directory)
Tuy nhiên, thay vì trả lại cho họ một đại diện độc lập với nền tảng của thư mục, họ đã thêm một cuộc gọi hệ thống mới - getdirents
- và bị cấm read
trên các thư mục gắn trên mạng. Cuộc gọi hệ thống này đã nhanh chóng được điều chỉnh để hoạt động trên tất cả các thư mục theo các hương vị UNIX khác nhau, làm cho nó trở thành cách mặc định để lấy nội dung của các thư mục. (Lịch sử được tóm tắt từ https://utcc.utoronto.ca/~cks/space/blog/unix/ReaddirHistory )
Bởi vì readdir
bây giờ là cách mặc định để đọc các thư mục, read(directory)
thường không được triển khai (trả về -EISDIR) trên hầu hết các hệ điều hành hiện đại (ví dụ, QNX, là một ngoại lệ đáng chú ý thực hiện readdir
như read(directory)
). Tuy nhiên, với thiết kế "hệ thống tập tin ảo" trong hầu hết các nhân hiện đại, nó thực sự tùy thuộc vào hệ thống tập tin riêng lẻ cho dù việc đọc một thư mục có hoạt động hay không.
Và thực tế, trên macOS, devfs
hệ thống tập tin nằm dưới /dev
mountpoint thực sự hỗ trợ việc đọc ( https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/miscfs/devfs/devfs_vnops.c#L629 ) :
static int
devfs_read(struct vnop_read_args *ap)
{
devnode_t * dn_p = VTODN(ap->a_vp);
switch (ap->a_vp->v_type) {
case VDIR: {
dn_p->dn_access = 1;
return VNOP_READDIR(ap->a_vp, ap->a_uio, 0, NULL, NULL, ap->a_context);
Điều này gọi một cách rõ ràng READDIR
nếu bạn cố đọc /dev
(đọc các tệp bên dưới /dev
được xử lý bởi một chức năng riêng biệt - devfsspec_read
). Vì vậy, nếu một chương trình gọi read
hệ thống gọi /dev
, nó sẽ thành công và có được danh sách thư mục!
Đây thực sự là một tính năng được nắm giữ từ những ngày đầu của UNIX và đã không được sử dụng trong một thời gian rất dài. Một phần trong tôi nghi ngờ rằng điều này đang được giữ xung quanh vì một số lý do tương thích ngược, nhưng nó có thể dễ dàng là thực tế rằng không ai quan tâm đủ để loại bỏ tính năng này vì nó không thực sự gây tổn hại gì.
Ít hơn là một trình xem tệp văn bản, cat là một công cụ để sao chép dữ liệu tùy ý. Vì vậy, ít thực hiện kiểm tra riêng của mình để đảm bảo rằng bạn không mở thứ gì đó sẽ có lượng dữ liệu khổng lồ hoặc hành xử rất kỳ lạ. Mặt khác, mèo hoàn toàn không kiểm tra như vậy - nếu hạt nhân cho phép bạn mở thứ gì đó (ngay cả khi đó là đường ống hoặc thiết bị hoặc thứ gì đó tệ hơn), mèo sẽ đọc nó.
Vậy tại sao HĐH cho phép mèo mở thư mục? Theo truyền thống trong các hệ thống kiểu BSD, tất cả các thư mục có thể được đọc dưới dạng tệp và đó là cách các chương trình sẽ liệt kê một thư mục ở vị trí đầu tiên: chỉ bằng cách diễn giải các cấu trúc dirent được lưu trữ trên đĩa.
Sau đó, các cấu trúc trên đĩa đó bắt đầu phân kỳ khỏi dirent được sử dụng bởi kernel: trong đó trước đó một thư mục là một danh sách tuyến tính, các hệ thống tập tin sau đó bắt đầu sử dụng hashtables, B-cây, v.v. Vì vậy, việc đọc các thư mục trực tiếp không còn đơn giản nữa - kernel đã phát triển các chức năng chuyên dụng cho việc này. (Tôi không chắc đó là lý do chính hay nếu chúng chủ yếu được thêm vào vì những lý do khác như bộ nhớ đệm.)
Một số hệ thống BSD tiếp tục cho phép bạn mở tất cả các thư mục để đọc; Tôi không biết liệu họ có cung cấp cho bạn dữ liệu thô từ đĩa hay không, liệu họ có trả lại danh sách dirent giả lập hay không, liệu họ có để trình điều khiển hệ thống tập tin quyết định hay không.
Vì vậy, có lẽ macOS là một trong những hệ điều hành mà kernel cho phép nó miễn là hệ thống tập tin cung cấp dữ liệu. Và sự khác biệt là /dev
trên một devfs
hệ thống tệp được viết để cho phép điều này trong những ngày đầu, trong khi /
trên hệ thống tệp APFS đã bỏ qua tính năng này là không cần thiết trong thời hiện đại.
Tuyên bố miễn trừ trách nhiệm: Tôi thực sự chưa thực hiện bất kỳ nghiên cứu nào về BSD hoặc macOS. Tôi chỉ đang bay nó.
/etc
sẽ, vì vậy tôi sử dụng nó như là điểm chuẩn của tôi.
mount
hoặc /sbin/mount
để xem những gì hiện đang được gắn kết ở đâu.
/dev
là một hệ thống tệp ảo sử dụng devfs
trình điều khiển trong khi đó /etc
là một phần của /
hệ thống tệp sử dụng apfs
trình điều khiển. Vì vậy, lý do cat
sẽ đọc một và không phải là một sự khác biệt giữa các trình điều khiển apfs
và devfs
.
neofetch
thông tin của bạn :) i.imgur.com/3azpnDt.png