Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Ruby

Chạy lệnh hệ thống trong Ruby: Best Practices & Kỹ thuật

Nếu bạn muốn chạy lệnh bên ngoài từ Ruby…

…như wkhtmltopdf để chuyển file HTML thành PDF.

Có một vài phương thức Ruby bạn có thể dùng.

Tùy vào phương pháp bạn dùng bạn sẽ nhận kết quả khác nhau.

Hãy khám phá các phương pháp này cùng nhau!

Phương thức System trong Ruby

Phương thức system trong Ruby là cách đơn giản nhất để chạy lệnh bên ngoài.

Trông như sau:

system("ls")

Chú ý system sẽ in output lệnh khi nó xảy ra.

Cũng system sẽ làm chương trình Ruby của bạn chờ cho đến khi lệnh xong.

Thử cái này:

system("sleep 2")

Có cách chạy lệnh trong background như chúng ta sẽ thấy sau.

System có thể trả về 3 giá trị có thể:

  • true nếu lệnh thành công
  • false nếu lệnh trả về mã lỗi
  • nil nếu thực thi lệnh thất bại (lệnh không tìm thấy)

Bạn có thể lấy mã trạng thái thoát của lệnh bên ngoài cuối cùng bạn chạy với biến global $?. Mã trạng thái này có thể cho bạn thêm thông tin về tại sao lệnh thất bại.

Shell Expansion là gì?

Khi bạn chạy lệnh bên ngoài với system, bạn sẽ nhận được hiệu ứng "shell expansion".

Shell expansion là khi shell (sh/bash/zsh) lấy một số ký tự đặc biệt (*, ?, và [) từ lệnh của bạn & mở rộng chúng thành danh sách file.

Ví dụ:

system("echo *")

Điều này sẽ in mọi file & thư mục trong thư mục hiện tại.

* được thay thế bằng danh sách file trước khi lệnh chạy.

Nếu bạn muốn dùng các ký tự đặc biệt này như chúng là truyền đối số làm đối số thứ 2 của system.

Như thế này:

system("echo", "*")

Bây giờ output sẽ là *.

Cách dùng Environment Variables (Biến môi trường)

Nếu bạn muốn truyền biến môi trường cụ thể cho lệnh bên ngoài bạn có thể dùng hash làm đối số đầu tiên.

Ví dụ:

system({"rubyguides" => "best"}, "ruby", "-e p ENV['rubyguides']") # "best"

Điều này sẽ không thay đổi môi trường hiện tại của ứng dụng Ruby của bạn.

%x / Kernel#`

Nếu bạn muốn lấy output từ lệnh bạn đang chạy, thay vì hiển thị nó, bạn có thể dùng %x hoặc phương thức Kernel#`.

Chúng làm cùng một việc.

Ví dụ:

`ls`

Ví dụ khác với %x:

%x|ls|

Hai ví dụ này sẽ trả về một chuỗi với output của lệnh ls.

Chú ý bạn vẫn phải chờ lệnh xong trừ khi bạn chạy nó trong thread.

Cách dùng Fork + Exec để chạy lệnh bên ngoài trên Process riêng

Forking tạo bản sao tiến trình hiện tại (app Ruby của bạn) sau đó bạn có thể thay thế bản sao đó bằng tiến trình khác dùng exec.

Lưu ý: Phương thức fork không có sẵn trên Windows.

Đây là pattern phổ biến trong thế giới Unix.

Cách hoạt động:

fork { exec("ls") }

Điều này sẽ chạy ls trên tiến trình khác & hiển thị output.

Bởi vì lệnh này chạy trên tiến trình khác, nó sẽ không block app Ruby của bạn chạy như phương thức system hoặc %x.

Quan trọng:

Nếu bạn dùng exec không có fork, bạn sẽ thay thế tiến trình hiện tại.

Điều này nghĩa là chương trình Ruby của bạn sẽ kết thúc.

Cách dùng Popen Method cho giao tiếp hai chiều với chương trình bên ngoài

Nếu bạn cần:

  • Kiểm soát nhiều hơn đối với tiến trình
  • Giao tiếp hai chiều

Thì phương thức IO.popen là thứ bạn đang tìm.

Trong ví dụ sau, tôi dùng popen để khởi chạy tiến trình irb, sau đó gửi input cho nó & đọc output.

Ví dụ:

r = IO.popen("irb", "r+")
r.write "puts 123 + 1\n"
3.times { puts r.gets }
r.write "exit\n"

Biến r này là object IO, nghĩa là bạn có thể ghi & đọc từ nó như file thông thường.

Dùng popen cũng nghĩa là lệnh bên ngoài sẽ chạy trên tiến trình riêng, nên bạn không phải chạy nó trên thread.

Cũng có phương thức popen3 trong thư viện chuẩn.

Khác biệt với popen thường là nó sẽ tách output thường & thông báo lỗi thành object IO riêng biệt.

Kết luận

Bạn đã học về các cách khác nhau bạn có thể tương tác với lệnh bên ngoài trong Ruby.

Hãy cẩn thận với những cái này!

Đừng truyền bất kỳ loại input người dùng nào vào các lệnh này trừ khi bạn muốn vấn đề bảo mật trong app Ruby của bạn.

Nếu bạn học được điều mới, hãy chia sẻ bài viết này để nhiều người hơn thấy nó.

Cảm ơn bạn đã đọc 🙂