Ruby, Sự khác biệt giữa exec, system và% x () hoặc Backticks


370

Sự khác biệt giữa các phương pháp Ruby sau đây là gì?

exec, system%x()hoặc Backticks

Tôi biết chúng được sử dụng để thực thi các lệnh đầu cuối theo chương trình thông qua Ruby, nhưng tôi muốn biết tại sao có ba cách khác nhau để làm điều này.


1
Những lệnh này, và nhiều người khác, được giải thích khá tốt trong các tài liệu: exec hệ thống backticks
zetetic

1
Có một bài viết tuyệt vời về Ruby Quicktips về chủ đề đó: Thực thi các lệnh shell .
Simon Perepelitsa

6
Vì ai đó vừa tìm ra chủ đề cũ này, "Làm việc với các quy trình Unix" là một cuốn sách tuyệt vời dành cho những người theo chủ nghĩa Ruby quan tâm đến chủ đề: workwithunix Processes.com
Michael Kohl

1
Tôi ngạc nhiên không có câu trả lời nào được đề cập sh.
Dennis

@Dennis Khi tôi đưa ra câu hỏi này, ruby ​​1.9.3 * không được phát hành.
Ông Đen

Câu trả lời:


411

hệ thống

Các systemphương pháp gọi là một chương trình hệ thống. Bạn phải cung cấp lệnh dưới dạng đối số chuỗi cho phương thức này. Ví dụ:

>> system("date")
Wed Sep 4 22:03:44 CEST 2013
=> true

Chương trình Viện dẫn sẽ sử dụng hiện nay STDIN, STDOUTSTDERRcác đối tượng của chương trình của Ruby của bạn. Trong thực tế, giá trị trả lại thực tế là true, falsehoặc nil. Trong ví dụ, ngày được in thông qua đối tượng IO của STDIN. Phương thức sẽ trả về truenếu quá trình thoát với trạng thái 0, falsenếu quá trình thoát với trạng thái khác không và nilnếu thực thi không thành công.

Một tác dụng phụ khác là biến toàn cục $?được đặt thành một Process::Statusđối tượng. Đối tượng này sẽ chứa thông tin về chính cuộc gọi, bao gồm cả định danh quy trình (PID) của quy trình được gọi và trạng thái thoát.

>> system("date")
Wed Sep 4 22:11:02 CEST 2013
=> true
>> $?
=> #<Process::Status: pid 15470 exit 0>

Backticks

Backticks (``) gọi một chương trình hệ thống và trả về đầu ra của nó. Trái ngược với cách tiếp cận đầu tiên, lệnh không được cung cấp thông qua một chuỗi, mà bằng cách đặt nó vào trong một cặp backticks.

>> `date`
=> Wed Sep 4 22:22:51 CEST 2013   

Biến toàn cục $?cũng được đặt thông qua backticks. Với backticks bạn cũng có thể sử dụng phép nội suy chuỗi.

% x ()

Sử dụng %xlà một thay thế cho phong cách backticks. Nó cũng sẽ trả lại đầu ra. Giống như người thân của nó %w%q(trong số những người khác), bất kỳ dấu phân cách nào cũng sẽ đủ miễn là các dấu phân cách kiểu khung khớp với nhau. Điều này có nghĩa %x(date), %x{date}%x-date-đều là từ đồng nghĩa. Giống như backticks %xcó thể sử dụng phép nội suy chuỗi.

thực hiện

Bằng cách sử dụng Kernel#execquy trình hiện tại (tập lệnh Ruby của bạn) được thay thế bằng quy trình được gọi qua exec. Phương thức có thể lấy một chuỗi làm đối số. Trong trường hợp này, chuỗi sẽ được mở rộng shell. Khi sử dụng nhiều hơn một đối số, thì đối số đầu tiên được sử dụng để thực thi chương trình và các đối số sau được cung cấp làm đối số cho chương trình được gọi.

Open3.popen3

Đôi khi thông tin bắt buộc được ghi vào đầu vào tiêu chuẩn hoặc lỗi tiêu chuẩn và bạn cũng cần kiểm soát những thông tin đó. Ở đây Open3.popen3có ích:

require 'open3'

Open3.popen3("curl http://example.com") do |stdin, stdout, stderr, thread|
   pid = thread.pid
   puts stdout.read.chomp
end

3
Và để kiểm soát hạt mịn hơn về cách thức xử lý cuộc gọi STDIN, STDOUT, STDERR, xem xét Open3.popen3thay; ví dụ: xem stackoverflow.com/a/10922097/258662
cboettig

1
Cảm ơn bạn đã đề cập rằng backticks hỗ trợ nội suy chuỗi đã giải quyết vấn đề của tôi.
adg

244

3
Điều này không đơn giản như vậy. Trong trường hợp của tôi, "đã ổn (và cần) để chặn cho đến khi quá trình hoàn tất" để sau đó sử dụng popen3 để kiểm tra các đầu ra STDOUT / STDERR.
Nakilon

Bạn luôn có thể gây ra một cuộc gọi không chặn đến (một cách hiệu quả) bằng cách gói nó trong một vòng lặp while. Bạn không thể thực hiện cuộc gọi chặn thành cuộc gọi không chặn dễ dàng như vậy.
Ian

106

Họ làm những việc khác nhau. execthay thế quy trình hiện tại bằng quy trình mới và không bao giờ quay trở lại . systemgọi một quy trình khác và trả về giá trị thoát của nó cho quy trình hiện tại. Sử dụng backticks gọi một quy trình khác và trả lại đầu ra của quy trình đó cho quy trình hiện tại.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.