`ps aux` được viết bằng Bash mà không cần fork
(github.com/izabera)izabera/pslà một triển khai bằng Bash nhằm mô phỏng đầu ra gần giốngps auxngay cả trong tình huống không thể tạo tiến trình mới- Điều kiện cốt lõi là: trên máy được truy cập qua
ssh, bạn có một bash shell đáng tin cậy, nhưng mọi PID khác đều đã bị dùng hết nên không thể tạo thêm tiến trình mới - README đưa tình huống này ra như một ví dụ về câu hỏi phỏng vấn cho các vị trí cần kiến thức về Bash/Linux
- Công cụ này được mô tả là giúp bạn “giả vờ như có thể truy cập
ps auxđang hoạt động”, chứ không bảo đảm là một bản thay thế hoàn chỉnh - Câu “hoạt động 100% trên mọi máy và trong mọi tình huống” rõ ràng được dùng như một cam kết mang tính đùa vui
Đây là dự án làm gì
- Đây là một dự án viết
ps auxchỉ bằng Bash - Tiêu đề README là “
ps auxwritten entirely in bash without ever forking” - Điểm đặc trưng cốt lõi của dự án là trong lúc chạy không fork dù chỉ một lần
Tình huống được giả định
- Tình huống ví dụ như sau
- Bạn đang truy cập máy qua
ssh - Người dùng đang ở trong một bash shell quen thuộc
- Nhưng mọi PID khác đều đã bị dùng hết nên hoàn toàn không thể tạo tiến trình mới
- Bạn đang truy cập máy qua
- README giới thiệu rằng trong điều kiện như vậy, bạn vẫn có thể cần một chức năng tương tự
ps aux
Phạm vi có thể kỳ vọng và caveat
- Công cụ này được giới thiệu là để bạn có thể “kinda sorta pretend” như thể có một
ps auxđang hoạt động - Câu trong README về việc “hoạt động hoàn hảo trong mọi tình huống trên 100% số máy, có bảo đảm” được dùng như một lối nói hài hước cường điệu
- Vì vậy, điểm chính trong phần mô tả không phải là khả năng tương thích hoàn toàn, mà là việc mô phỏng
ps auxchỉ bằng Bash trong môi trường cực đoan nơi không thể tạo tiến trình mới
1 bình luận
Các ý kiến trên Hacker News
Câu đùa rằng rốt cuộc vấn đề khó nhất trong khoa học máy tính lại là căn chỉnh nghe rất thấm
Tôi đã viết vô số hàm căn cột bằng nhiều ngôn ngữ, lần nào cũng khổ sở; trong đầu thì trông đơn giản kiểu “tìm độ dài lớn nhất của từng cột rồi thêm khoảng trắng đến bội số tiếp theo của kích thước tab”
Ngay cả khi dùng f-string và tính năng padding của Python, mã cũng nhanh chóng trở nên phức tạp và khó đọc; kinh khủng đến mức khi viết lại ví dụ cho bình luận, tôi cũng đã sửa vài lỗi
Với một nhu cầu phổ biến thế này, đáng ra phải có thư viện là chuyện hiển nhiên; nói thật là tôi ngạc nhiên vì nó không có trong thư viện chuẩn
Cách làm là lấy độ rộng và tên cột từ
descriptioncủa database cursor, tạo đường phân cách và chuỗi định dạng rồi in các hàng; tôi không biết có lỗi chí mạng nào bị bỏ sót không, nhưng nó không có vẻ là một vấn đề đặc biệt khózip(*table)để xoay các cột, tìm độ dài lớn nhất của từng cột, rồi in căn chỉnh bằngf"{r:<{w}}"Kết quả ví dụ sẽ là một bảng có độ rộng cột được căn như
agony | kick | pumpGiá trị có khoảng trắng bên trong, được đệm bằng khoảng trắng, đôi khi bị lệch căn chỉnh và còn tràn qua cột
Có lẽ nếu tất cả cùng thống nhất không dùng dữ liệu căn cột mà dùng một định dạng đơn giản hơn, con người vẫn đọc được, thì ai cũng có lợi
Nếu đang SSH vào một máy mà shell Bash vẫn còn sống nhưng mọi PID đã cạn nên không thể tạo tiến trình mới, tôi sẽ lục hệ thống tệp
/proc/[pid]/để xem tiến trình nào đang làm cạn kiệt không gian PIDkillcủa Bash là lệnh tích hợp sẵn trong shell nên không cần fork tiến trình mới như/bin/killNếu tìm được tiến trình cha đang sinh ra các tiến trình con làm cạn PID, có thể dừng nó và giành lại quyền kiểm soát hệ thống
Script này cũng phân tích
/proc, và không có pipe hay phép thế$(...)tạo subshell Bash mới, nên khá gọn gàngNhư vậy có thể gọi các hàm POSIX cần thiết mà không phải chạy lệnh riêng, nên đã nhận được phản ứng tốt
Khởi động lại rồi khôi phục có thể nhanh hơn việc tìm và giết tiến trình cha trong môi trường bị hạn chế, và nếu PID đã cạn thì nhiều thứ khác có lẽ cũng đã ở trạng thái tệ
ps(){ (cd /proc;for i in [0-9]*;do echo $i: $(tr '\0' ' ' < $i/cmdline);done); }/proc/[pid]/để biết tiến trình nào làm cạn không gian PID là đúng, nhưng nhìn chú thích trong mã nguồn thì ban đầu tác giả hy vọng chỉ/proc/*/statuslà đủ, tuy nhiên các giá trị như mức sử dụng CPU lại không lấy được ở đó[[ $cmdline ]] && exec {cmdline}>&-vàexec {cmdline}< "$dir"/cmdline || continuehoạt động như thế nàoNăm 2011, tôi phỏng vấn cho một vai trò SRE ở một công ty công nghệ khá lớn tại Mỹ; khi đó tôi còn lần đầu nghe thuật ngữ SRE
Công ty đó đang làm một giải pháp thay thế MS Office chạy trên trình duyệt, và sau vòng sàng lọc qua điện thoại, tôi phải lập trình thời gian thực khi đang nói chuyện với người phỏng vấn bên trong trình biên tập tài liệu của công ty
Vì trong bảng tự đánh giá tôi ghi điểm cao cho
shell scriptingvàLinux, tôi được giao bài làm một bản thay thếnetstatbằng Bash, nhưng lúc đó tôi không biết thông tin socket nằm ở đâu và như thế nào trong/proc/, nên nhanh chóng kết luận là mình không làm đượcThay vào đó, tôi đề xuất làm một bản thu gọn của
psvàfuser, và lời giải tôi đưa ra trong cái trình xử lý văn bản nền trình duyệt tệ hại đó đã được chấp nhận, giúp tôi vào vòng phỏng vấn onsiteNghĩ lại thì có lẽ kịch bản giả định làm động cơ cho bài tập này bắt nguồn từ thực tế nhiều hơn tôi tưởng
Nếu là tôi, tôi cũng sẽ bắt đầu từ đó
Trước đây tôi từng làm cho vui một website tương tác để khám phá tình huống đang SSH vào mà không thể tạo tiến trình mới: https://oops.cmdchallenge.com
"echo *"không liệt kê mọi tệp trong thư mụcPhải dùng
"echo .* *"Tôi muốn xem danh sách
"View Solutions"của các bước khác để biết còn có những cách tiếp cận nàoIzabera là một trong các cao thủ của #bash@libera
Từ thời freenode ngày trước, tôi đã học được thật sự rất nhiều từ những cao thủ như vậy trong suốt 10 năm qua
Đây là Bash khá sạch sẽ
Theo kinh nghiệm của tôi, mã Bash thường được viết tệ và kém hiệu quả, nhưng mã này có vẻ là một ví dụ tốt không như vậy
Nếu đang ở trong một POSIX shell đáng tin cậy nhưng không hỗ trợ Bash thì phải làm sao?
Script Bash này không tương thích POSIX
Script này không chạy trên Bash 3.2, nhưng chạy được trên Bash 4.2
Trên Bash 3.2 sẽ báo lỗi
printf: '(': invalid format character, và môi trường ví dụ làbash-3.2-33.el5_11.4.0.1Ứng dụng hay hơn có lẽ là xem danh sách tiến trình trên hệ thống không cài procps
Ổn đấy
Cũng có thể tạo listener và client bằng Bash
Không khuyến nghị dùng trong thực tế