1 điểm bởi GN⁺ 2024-07-30 | 1 bình luận | Chia sẻ qua WhatsApp
  • izabera/ps là một triển khai bằng Bash nhằm mô phỏng đầu ra gần giống ps aux ngay 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 aux chỉ bằng Bash
  • Tiêu đề README là “ps aux written 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
  • 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 aux chỉ 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

 
GN⁺ 2024-07-30
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

    • Tôi từng thêm Pandas vào một dự án chỉ vì không muốn tự viết kiểu mã như vậy để in ra bảng đẹp
      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
    • https://perldoc.perl.org/perlform
    • Trước đây tôi từng trả lời trên Stack Overflow bằng một lời giải O(n): https://stackoverflow.com/questions/10865483/print-results-i...
      Cách làm là lấy độ rộng và tên cột từ description củ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ó
    • Đơn giản hơn nữa, có thể dùng 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ằng f"{r:<{w}}"
      Kết quả ví dụ sẽ là một bảng có độ rộng cột được căn như agony | kick | pump
    • Ngược lại, từ góc nhìn của người thường xuyên phải phân tích dữ liệu đã căn cột, chuyện này cũng không dễ
      Giá 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 PID
    kill củ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/kill
    Nế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àng

    • Trong một buổi phỏng vấn, tôi từng trả lời là “exec Python
      Như 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
    • Nói thật thì nếu là tôi, có lẽ tôi sẽ chỉ khởi động lại
      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ệ
    • Nếu chỉ muốn xem PID và tên lệnh, gần như có thể viết tối giản như sau: ps(){ (cd /proc;for i in [0-9]*;do echo $i: $(tr '\0' ' ' < $i/cmdline);done); }
    • Nói rằng sẽ xem trong /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/*/status là đủ, tuy nhiên các giá trị như mức sử dụng CPU lại không lấy được ở đó
    • Liên quan đến subprocess, tôi thật sự tò mò [[ $cmdline ]] && exec {cmdline}>&-exec {cmdline}< "$dir"/cmdline || continue hoạt động như thế nào
  • Nă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 scriptingLinux, tôi được giao bài làm một bản thay thế netstat bằ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 được
    Thay vào đó, tôi đề xuất làm một bản thu gọn của psfuser, 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 onsite
    Nghĩ 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

    • Một số tiện ích hệ thống kiểu này dù sao cũng nhiều khả năng đang nhìn vào procfs/sysfs bên trong
      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ục
      Phải dùng "echo .* *"
    • Hay thì hay, nhưng sau khi hoàn thành nó lại đưa tôi về bước đầu tiên và không cho xem các bước khác, nên khá bực
      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ào
  • Izabera 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 là Bash sạch sẽ thì cũng nên có tính di động, nhưng script này chỉ dành cho Linux và sẽ hỏng nặng ở nơi khác
  • 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

    • Tôi thấy việc không hỗ trợ một nhánh phát hành Bash 18 năm tuổi và một nhánh phát hành hệ điều hành 17 năm tuổi là hoàn toàn hợp lý
  • Ứ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ế