2015-06-19 14 views
6

Trong một kịch bản Ruby, có various ways để gọi lệnh hệ thống/dòng lệnhLàm thế nào để tập lệnh Ruby thất bại khi lệnh shell-out trả về với mã thoát khác không?

  1. backticks: `command arg1 arg2`
  2. hình thức phân định, ví dụ %x(command arg1 arg2) (delimiters khác có sẵn)
  3. Kernel#system phương pháp: system('command arg1 arg2')
  4. Kernel#exec phương pháp: exec('command arg1 arg2')

Nếu tôi muốn kịch bản Ruby để thất bại (với một ngoại lệ) khi gọi lệnh thất bại (với một tổ chức phi-zero exit code) tôi có thể kiểm tra cho mã thoát trong biến đặc biệt $? cho hai phiên bản đầu tiên:

`command arg1 arg2` 
fail unless $? == 0 

hoặc

%x,command arg1 arg2, 
fail unless $? == 0 

Nếu tôi tốt với đầu ra tiêu chuẩn của lệnh sẽ đầu ra tiêu chuẩn kịch bản Ruby (và tôi), tôi có thể sử dụng biến thể 3 và kiểm tra giá trị trả về của nó:

unless system('command arg1 arg2') 
    fail 
end 

Nếu tôi không quan tâm đến khả năng giải cứu ngoại lệ cũng như về hành vi in ​​ngăn xếp của các ngoại lệ không được lưu giữ, tất nhiên tôi có thể sử dụng exit(1) hoặc trong hai biến thể đầu tiên exit($?) thay cho fail.

Nếu tiếp tục thực hiện các lệnh là điều cuối cùng kịch bản Ruby nên làm, ngay cả khi lệnh thành công (exit đang 0), tôi có thể sử dụng các biến thể thứ tư:

exec('command arg1 arg2') 

này sẽ thay thế Quá trình Ruby với quy trình mới được tạo bằng cách gọi lệnh, nhưng hiệu ứng cho người gọi của tập lệnh Ruby sẽ giống nhau: Anh ta nhìn thấy mã thoát không chính xác nếu lệnh được gọi gây ra một mã thoát khác không.

Tôi rất thích sự phù hợp của biến thể thứ tư, nhưng nếu thực hiện lệnh không phải là điều cuối cùng cần làm trong trường hợp thành công, tôi không may không sử dụng nó. Điều kiện fail hoặc exit các lời gọi của các biến thể khác trông rất ô uế khi so sánh và trong một lần sử dụng của chúng tôi thường xuyên hơn là không vi phạm nguyên tắc trừu tượng và trách nhiệm duy nhất. Tất nhiên tôi có thể dễ dàng viết một hàm bao bọc cho bất kỳ cách nào trong ba phương pháp đầu tiên để sử dụng chúng giống như súc tích, nhưng vì điều này có vẻ giống như một toán tử cơ bản, Tôi tự hỏi liệu Ruby đã có thứ gì đó như thế chưa được xây dựng trong ... có thể là một chức năng tiện ích mà tôi có thể sử dụng thay vì một trình bao bọc của riêng mình hoặc một cơ chế thay đổi hành vi của một hoặc một số phương pháp gọi lệnh gây ra lỗi hoặc một lối thoát khác 0 lệnh không thành công, tương tự với 's và ' s option to set -e.

Trả lời

4

Theo như tôi biết không có cách nào tích hợp để làm điều này, nhưng bạn gần như có thể nhận được hành vi mà bạn muốn với một lập trình meta chút ma thuật

def set_exit enable 
    if enable 
    define_method :system do |*args| 
     Kernel.system *args 
     exit $?.exitstatus unless $?.success? 
    end 
    else 
    define_method :system, Kernel.instance_method(:system) 
    end 
end 

set_exit true 
# ... 
# any failed system calls here will cause your script to exit 
# ... 
set_exit false 
# now system is back to normal 

này hoạt động bằng cách xác định lại system cho Object, trong khi sử dụng rõ ràng Kernel.system khi có hành vi tích hợp.

+1

Tốt. Vì [backquotes sử dụng 'Kernel # \' '] (http://ruby-doc.com/docs/ProgrammingRuby/html/tut_expressions.html#UB), tôi đoán phương pháp này cũng có thể làm việc cho chúng. –

+0

Chà, tôi không biết đó thực sự là một phương pháp! Có vẻ như nó hoạt động tốt nếu bạn thay thế ': \' 'cho': system' – Max

Các vấn đề liên quan