Chia sẻ đam mê công nghệ
Giải thích

Vì sao Linux coi mọi thứ là file, kể cả ổ đĩa và trạng thái pin?

Cùng một lệnh đọc có thể xem nội dung tài liệu hoặc trạng thái kernel trên Linux. Thiết kế kế thừa từ Unix này giúp ghép công cụ rất tiện, nhưng cũng đòi hỏi hiểu rõ mình đang ghi vào đâu.

Laptop Framework chạy Arch Linux với Hyprland
Desktop Linux có thể tùy biến nhiều, nhưng cách truy cập tài nguyên qua file mới là phần khác biệt nằm sâu dưới giao diện. Ảnh: XDA Developers.

Tóm tắt nhanh

  • Linux kế thừa từ Unix cách dùng giao diện đọc, ghi file để làm việc với nhiều loại tài nguyên, thay vì buộc mỗi loại có một bộ công cụ hoàn toàn riêng.
  • /dev đại diện cho thiết bị và một số thiết bị ảo; /proc và /sys đưa thông tin của kernel ra ngoài qua hệ thống file ảo.
  • Pipe giúp nối các chương trình nhỏ thành chuỗi xử lý, còn PowerShell thường truyền đối tượng có cấu trúc giữa các lệnh.
  • Giao diện giống file không có nghĩa dữ liệu nằm trên đĩa, cũng không có nghĩa ghi vào tài nguyên đó là an toàn.

Trên Linux, trạng thái pin có thể được đọc từ một đường dẫn, còn cả ổ đĩa cũng có thể xuất hiện dưới dạng một mục trong cây thư mục. Cảm giác khác lạ ấy bắt nguồn từ thiết kế Unix đã tồn tại hơn nửa thế kỷ: đưa nhiều tài nguyên về một giao diện làm việc chung với file.

Điểm đáng học ở thiết kế này là cách giảm số quy tắc người dùng và chương trình phải nhớ. Nhưng nếu hiểu câu “everything is a file” theo nghĩa đen, người mới lại rất dễ nhầm giữa đọc một thuộc tính, sửa file cấu hình và ghi thẳng lên thiết bị lưu trữ. Cùng dùng thao tác đọc hoặc ghi, hậu quả của chúng có thể khác hẳn nhau.

Điều được thống nhất là cách truy cập, không phải bản chất dữ liệu

Một file văn bản thông thường chứa các byte lưu trên thiết bị lưu trữ. Chương trình mở file, nhận một file descriptor, dùng nó để đọc hoặc ghi rồi đóng lại khi hoàn tất. File descriptor có thể hiểu là số định danh mà tiến trình dùng để tham chiếu tới tài nguyên đã mở; nó không phải tên file và cũng không phải chính dữ liệu của file.

Thiết kế Unix mở rộng cách làm ấy sang các file đặc biệt đại diện cho thiết bị. Chương trình vẫn có thể dùng những thao tác vào ra quen thuộc, còn phần xử lý phù hợp với thiết bị nằm phía dưới giao diện đó. Nhờ vậy, công cụ không nhất thiết phải biết toàn bộ chi tiết phần cứng trước khi đọc được một luồng dữ liệu.

Bài mô tả Unix năm 1974 của Dennis Ritchie và Ken Thompson phân biệt file thông thường, thư mục và file đặc biệt dành cho thiết bị vào ra. Mốc này cho thấy ý tưởng đã có từ trước Linux rất lâu; gọi đây là một sáng kiến mới của các bản phân phối Linux hiện nay sẽ sai về lịch sử.

Tuy nhiên, có chung giao diện không khiến mọi tài nguyên có chung khả năng. Đọc một chuỗi byte chưa cho biết chuỗi ấy là văn bản, dữ liệu nhị phân hay trạng thái thiết bị. Chương trình vẫn phải biết cách diễn giải nội dung, còn những thao tác đặc thù có thể cần cơ chế điều khiển riêng. Một công cụ đọc văn bản không tự nhiên hiểu được toàn bộ chức năng của phần cứng chỉ vì phần cứng có mục trong /dev.

Vì thế, cách hiểu hữu ích hơn là Linux cố gắng tái sử dụng giao diện file ở nhiều nơi. Đó là một lựa chọn thiết kế giúp các công cụ phối hợp với nhau, chứ không phải lời khẳng định rằng mọi thành phần của hệ điều hành đều là tài liệu có thể mở bằng trình soạn thảo.

/proc và /sys cho đọc trạng thái mà không cần lưu thành tài liệu

Kết quả cat /proc/cpuinfo trong terminal Linux
cat /proc/cpuinfo đọc thông tin CPU qua hệ thống file ảo, thay vì mở một tài liệu thông số lưu trên ổ đĩa. Ảnh: XDA Developers.

Một đường dẫn trông giống file chưa chắc dẫn tới dữ liệu đã ghi trên SSD. Trong /proc và /sys, thứ người dùng nhìn thấy chủ yếu là giao diện tới thông tin hoặc thuộc tính do kernel cung cấp. Nội dung có thể được tạo ra khi đọc, thay vì tồn tại sẵn dưới dạng một tài liệu trên đĩa.

Chẳng hạn, cat /proc/cpuinfo đọc thông tin CPU, còn cat /proc/meminfo cho xem thông tin bộ nhớ. Người dùng không cần tìm một ứng dụng giao diện đồ họa riêng cho từng nhóm thông tin ấy. Thao tác vẫn là đọc file, nhưng nguồn dữ liệu thực sự là trạng thái mà hệ điều hành đang công bố.

/sys đi theo hướng biểu diễn mô hình thiết bị và thuộc tính của kernel. Tài liệu Linux Kernel mô tả sysfs là hệ thống file dựa trên RAM, xuất cấu trúc dữ liệu cùng quan hệ giữa các đối tượng ra không gian người dùng. Các thư mục thể hiện quan hệ giữa đối tượng, còn thuộc tính được đưa ra dưới dạng file, với định hướng ưu tiên văn bản ASCII và một giá trị cho mỗi file.

Cách tổ chức này giải thích vì sao một đường dẫn như /sys/class/power_supply/BAT0/capacity có thể trả về mức pin dưới dạng phần trăm. Đây là ví dụ về thiết bị có tên BAT0, không phải đường dẫn đảm bảo đúng cho mọi laptop: tên thiết bị và thuộc tính khả dụng còn phụ thuộc máy cùng driver. Không thấy đúng đường dẫn đó không đồng nghĩa hệ điều hành không nhận pin.

Phía dưới, đọc thuộc tính sysfs được chuyển tới hàm cung cấp giá trị, còn ghi thuộc tính được chuyển tới hàm tiếp nhận thay đổi nếu thuộc tính cho phép. Nhìn từ dòng lệnh thì đó là đọc hoặc ghi file; nhìn từ phía kernel thì có mã xử lý đang chạy. Vì vậy, mở được một file để đọc không cho phép suy ra rằng nó cũng ghi được, hoặc có thể chỉnh tùy ý như một dòng trong tài liệu.

Đây là khác biệt quan trọng khi xử lý sự cố: thông tin trạng thái không phải lúc nào cũng là cấu hình bền vững. Một giá trị thấy trong /sys cần được hiểu theo đúng thuộc tính của nó, thay vì mặc định rằng sửa xong sẽ được lưu lại như sửa một file trên phân vùng hệ thống.

Pipe biến công cụ nhỏ thành chuỗi xử lý có ích

Terminal hiển thị ví dụ lệnh grep
grep chỉ cần đầu vào văn bản để lọc mẫu, không phải hiểu toàn bộ nơi sinh ra dữ liệu. Ảnh: XDA Developers.

Giá trị dễ nhận ra nhất của giao diện thống nhất nằm ở khả năng ghép chương trình. Khi một công cụ xuất văn bản và công cụ khác đọc được văn bản, người dùng có thể nối chúng bằng pipe, thay vì chờ một ứng dụng lớn tích hợp đủ mọi bộ lọc mình cần.

journalctl kết hợp grep lọc nhật ký Bluetooth
Kết hợp journalctl với grep tách việc lấy nhật ký và lọc dòng thành hai bước có thể ghép lại. Ảnh: XDA Developers.

Ví dụ, chuỗi lệnh chỉ đọc cat /proc/meminfo | grep MemAvailable dùng cat để đưa nội dung ra đầu ra chuẩn, sau đó chuyển luồng ấy cho grep lọc dòng chứa MemAvailable. grep không cần biết nội dung ban đầu đến từ hệ thống file ảo. Nó chỉ làm công việc tìm mẫu trên dữ liệu nhận được.

Ví dụ ấy cũng cho thấy sức mạnh không nằm ở việc phải ghép thật nhiều lệnh. Có thể dùng trực tiếp grep MemAvailable /proc/meminfo khi chỉ cần lọc một file. Pipe hữu ích khi đầu vào là kết quả của một chương trình khác, hoặc khi cần ghép nhiều bước mà từng chương trình riêng lẻ không đảm nhiệm toàn bộ.

Ảnh terminal lọc nhật ký bằng journalctl và grep thể hiện đúng kiểu phối hợp này: chương trình đọc nhật ký lo việc lấy dữ liệu, còn grep lo phần chọn dòng. Lợi ích đối với việc quản trị một máy Linux, kể cả máy chủ chạy từ xa, là có thể xây một chuỗi xử lý từ công cụ sẵn có mà không phải mở ứng dụng đồ họa.

Đổi lại, văn bản không tự mang đầy đủ ý nghĩa của từng trường. Công cụ lọc cần biết mẫu cần tìm, định dạng kết quả và cách xử lý trường hợp không có dòng phù hợp. Ghép lệnh ngắn chưa chắc đã là một quy trình chắc chắn nếu người viết không hiểu dữ liệu đang đi qua từng đoạn.

/dev là nơi sự tiện lợi có thể trở thành rủi ro ghi nhầm

smartctl truy cập thiết bị /dev/sda trên Proxmox
smartctl truy cập /dev/sda để hỏi thông tin ổ đĩa: tên đường dẫn thiết bị cần được nhận diện đúng trước mọi thao tác. Ảnh: XDA Developers.

File thiết bị giúp cùng một công cụ sao chép làm việc với cả ảnh đĩa lẫn thiết bị lưu trữ, nhưng cũng thu hẹp khoảng cách giữa một lệnh bình thường và thao tác có thể làm mất dữ liệu. Đây là mặt đánh đổi cần hiểu trước khi chạy lệnh quản trị lấy từ Internet.

Trong /dev, một ổ SATA có thể xuất hiện dưới tên như /dev/sda, còn một thiết bị NVMe có thể có tên như /dev/nvme0n1. Các phân vùng có mục đại diện riêng. Đường dẫn tới cả ổ và đường dẫn tới một phân vùng không thể dùng thay nhau chỉ vì tên nhìn gần giống.

Với công cụ dd, ghi ảnh đĩa vào đúng thiết bị có thể là một cách tạo USB khởi động khi định dạng ảnh hỗ trợ cách ghi đó. Nhưng nếu chọn nhầm đầu ra thành ổ chứa dữ liệu, thao tác ghi không còn là tạo thêm một file: nó có thể ghi đè dữ liệu trực tiếp trên thiết bị đích. Khả năng dùng chung giao diện không cung cấp sẵn một bước xác nhận đủ thông minh để nhận ra ý định của người dùng.

Bởi vậy, ưu tiên công cụ có giao diện chọn thiết bị rõ ràng là lựa chọn hợp lý cho người chỉ thỉnh thoảng tạo USB cài hệ điều hành. Nếu buộc phải dùng dòng lệnh, phải xác định đúng thiết bị đích và có bản sao lưu trước thao tác ghi; không nên sao chép nguyên một ví dụ có tên ổ đĩa của máy khác rồi chạy với quyền quản trị.

Không phải mục nào trong /dev cũng có phần cứng thật phía sau. /dev/null bỏ dữ liệu được ghi vào, /dev/zero cung cấp các byte bằng không, còn /dev/urandom cung cấp byte ngẫu nhiên. Các ví dụ này cho thấy tên gọi “file thiết bị” mô tả một giao diện phục vụ vào ra, chứ không đảm bảo có một linh kiện vật lý tương ứng trong máy.

Windows chọn cách khác, không có nghĩa thiếu khả năng tự động hóa

Thông tin Arch Linux trong Konsole
Một công cụ hiển thị thông tin như neofetch nằm ở tầng sử dụng dữ liệu, khác với giao diện kernel công bố dữ liệu đó. Ảnh: XDA Developers.

Khác biệt đáng chú ý giữa Linux và Windows nằm ở cách phơi bày tài nguyên cùng thói quen xây công cụ, chứ không phải bên nào có hoặc không có tài nguyên được quản lý thống nhất. Lấy khả năng đọc một đường dẫn trên Linux để kết luận Windows không làm được tác vụ tương đương là so sánh quá vội.

Windows NT có Object Manager quản lý các đối tượng kernel trong không gian tên riêng, còn chương trình truy cập tài nguyên qua handle. Không gian tên này không đơn giản đồng nhất với cây thư mục file mà người dùng thường duyệt. Trên Linux, nhiều giao diện thiết bị và trạng thái lại hiện diện ngay trong cây thư mục quen thuộc, khiến thói quen mở terminal để đọc một đường dẫn trở nên tự nhiên hơn.

Ở tầng dòng lệnh, PowerShell thường truyền đối tượng .NET có cấu trúc giữa các lệnh thay vì chỉ chuyển văn bản. Khi dữ liệu đã có thuộc tính, công cụ tiếp theo có thể làm việc với thuộc tính ấy, thay vì phải tách một cột chữ từ kết quả hiển thị. Còn cách làm dựa trên luồng văn bản thuận tiện khi cần phối hợp những chương trình có thể đọc và xuất cùng loại dữ liệu ấy.

Đây không phải cuộc so đơn giản xem pipe hay đối tượng tốt hơn trong mọi trường hợp. Với công việc đã có công cụ Unix xuất văn bản phù hợp, ghép lệnh là cách trực tiếp. Với dữ liệu có cấu trúc sẵn trong PowerShell, cố biến mọi thứ thành chuỗi rồi phân tích lại có thể làm công việc phức tạp hơn. Học đúng kiểu dữ liệu của môi trường đang dùng có ích hơn việc ép hệ điều hành mới bắt chước hệ điều hành cũ.

Người chuyển sang Linux nên học ranh giới trước khi học mẹo lệnh

Laptop trong quá trình cài Arch Linux
Cài Linux là lúc cần phân biệt rõ thiết bị lưu trữ với file thông thường trước khi chạy lệnh ghi. Ảnh: XDA Developers.

Thói quen có lợi nhất cho người mới là phân biệt mình đang đọc trạng thái, sửa cấu hình hay điều khiển thiết bị. Cả ba có thể dùng đường dẫn và lệnh ghi, nhưng không có cùng mức rủi ro và cũng không có cùng cách lưu thay đổi.

Laptop Framework chạy Linux với công cụ giám sát trong terminal
Công cụ giám sát giúp đọc trạng thái Linux dễ hơn, còn các giao diện bên dưới cho phép tiếp tục tự động hóa tác vụ. Ảnh: XDA Developers.

Đọc /proc/meminfo là một cách quan sát. Đọc thuộc tính trong /sys là hỏi kernel về một giá trị. Ghi vào một thuộc tính cho phép ghi có thể yêu cầu thay đổi hành vi, trong khi ghi trực tiếp vào thiết bị lưu trữ có thể thay đổi dữ liệu trên ổ. Chỉ nhớ cú pháp mà bỏ qua loại đích đến sẽ khiến những lệnh ngắn trông vô hại hơn thực tế.

Câu “mọi thứ là file” còn có giới hạn: Linux vẫn dùng những cơ chế giao tiếp như D-Bus và Netlink, không phải mọi đối tượng đều có một tên file để mở bằng cách thông thường. File descriptor cũng rộng hơn hình dung về tài liệu nằm trong thư mục. Xem khẩu quyết này như quy tắc tuyệt đối sẽ che mất chính những khác biệt cần biết khi tìm lỗi.

Đối với người chuyển từ Windows sang Linux để học lập trình hoặc quản trị máy chủ, điều nên giữ lại là cách đặt câu hỏi: tài nguyên này được công bố qua giao diện nào, đọc có tác dụng gì, ghi sẽ thay đổi thứ gì? Khi trả lời được những câu ấy, cây thư mục Linux bớt bí hiểm; còn một dòng lệnh ngắn sẽ được đánh giá theo tác động thật, không theo vẻ đơn giản của nó.

Nguồn tham khảo: Linux Kernel — tài liệu sysfs; XDA Developers — giao diện file trên Linux và Unix; Wikipedia — Everything is a file.

Bài này thế nào?

Theo dõi TekCafe: Facebook · YouTube

Bài viết mới nhất