2010-01-18 40 views
94

Tôi đã được thông qua một chương trình di sản ruby ​​chạy dài, trong đó có nhiều lần xuất hiện củachụp Ctrl-c trong ruby ​​

begin 
    #dosomething 
rescue Exception => e 
    #halt the exception's progress 
end 

suốt nó.

Nếu không theo dõi xuống mỗi thể ngoại lệ duy nhất này từng có thể được xử lý (ít nhất là không ngay lập tức), tôi vẫn muốn để có thể đóng cửa vào những thời điểm với CtrlC.

Và tôi muốn làm như vậy trong một cách mà chỉ thêm vào đoạn code (vì vậy tôi không ảnh hưởng đến hành vi hiện tại, hoặc bỏ lỡ một ngoại lệ khác đánh bắt ở giữa của một hoạt động.)

[CtrlC là SIGINT hoặc SystemExit, có vẻ tương đương với SignalException.new("INT") trong hệ thống xử lý ngoại lệ của Ruby. class SignalException < Exception, đó là lý do tại sao vấn đề này đi lên]

Mã Tôi muốn có văn bản sẽ là:.

begin 
    #dosomething 
rescue SignalException => e 
    raise e 
rescue Exception => e 
    #halt the exception's progress 
end 

EDIT: Mã này hoạt động, miễn là bạn sẽ có được lớp của ngoại lệ bạn muốn bẫy đúng. Đó là SystemExit, Interrupt hoặc IRB :: Abort như dưới đây.

Trả lời

113

Vấn đề là khi chương trình Ruby kết thúc, nó thực hiện bằng cách tăng SystemExit. Khi điều khiển C đi vào, nó tăng Ngắt. Vì cả hai SystemExitNgắt xuất phát từ Ngoại lệ, xử lý ngoại lệ của bạn sẽ ngừng thoát hoặc gián đoạn trong tuyến đường. Dưới đây là sửa chữa:

Bất cứ nơi nào bạn có thể, thay đổi

rescue Exception => e 
    # ... 
end 

để

rescue StandardError => e 
    # ... 
end 

cho những bạn không thể thay đổi để StandardError, tái nâng cao ngoại lệ:

rescue Exception => e 
    # ... 
    raise 
end 

hoặc, ít nhất, nâng cấp lại SystemExit và Ngắt

rescue SystemExit, Interrupt 
    raise 
rescue Exception => e 
    #... 
end 

Bất kỳ trường hợp ngoại lệ tùy chỉnh bạn đã thực hiện nên xuất phát từ StandardError, không Exception.

+0

Wayne, bạn sẽ rất tử tế khi thêm một IRB :: Ví dụ hủy bỏ vào danh sách của bạn? –

+1

@Tim, đi tìm irb.rb (trên hệ thống của tôi, nó nằm trong /usr/lib/ruby/1.8/irb.rb) và tìm vòng lặp chính (tìm kiếm @ context.evaluate). Nhìn vào các điều khoản giải cứu và tôi nghĩ bạn sẽ hiểu tại sao IRB hành xử theo cách đó. –

+0

cảm ơn bạn. Nhìn vào định nghĩa cho #signal_handle trong irb.rb cũng giúp tôi hiểu. Họ có một thủ thuật gọn gàng trong vòng lặp chính của biến ngoại lệ ràng buộc là tốt. (Sử dụng các mệnh đề giải cứu như một cách để chọn ra một ngoại lệ cụ thể, sau đó sử dụng ngoại lệ đó bên ngoài các cơ quan cứu hộ.) –

63

Nếu bạn có thể bọc toàn bộ chương trình của bạn, bạn có thể làm điều gì đó như sau:

trap("SIGINT") { throw :ctrl_c } 

catch :ctrl_c do 
begin 
    sleep(10) 
rescue Exception 
    puts "Not printed" 
end 
end 

về cơ bản có CtrlC sử dụng đánh bắt này/ném thay vì xử lý ngoại lệ, vì vậy trừ khi mã hiện đã có một bắt: ctrl_c trong nó, nó sẽ được sử dụng tốt.

Hoặc bạn có thể thực hiện trap("SIGINT") { exit! }. exit! thoát ngay lập tức, nó không tăng ngoại lệ để mã không thể vô tình bắt được nó.

+2

Lưu ý rằng Ctrl-C trong IRB gửi IRB :: Hủy bỏ, chứ không phải SIGINT. Nếu không thì câu trả lời của Logan là một giải pháp. –

+1

@TimSnowhite cho thông dịch viên ruby ​​'SIGINT' hoạt động tốt cho tôi. – defhlt

+1

ném và bắt phải nằm trên cùng một chuỗi, do đó, điều này sẽ không hoạt động nếu bạn muốn bắt ngoại lệ gián đoạn trên một chuỗi khác. –

25

Nếu bạn không thể quấn toàn bộ ứng dụng của bạn trong một khối begin ... rescue (ví dụ, Thor), bạn có thể chỉ bẫy SIGINT:

trap "SIGINT" do 
    puts "Exiting" 
    exit 130 
end 

130 là một mã lối ra tiêu chuẩn.

+0

FYI, 130 là mã thoát chính xác cho các tập lệnh bị gián đoạn Ctrl-C: https://www.google.com/search?q=130+exit+code&en= ('130 | Tập lệnh chấm dứt bằng Control-C | Ctl-C | Control-C là tín hiệu lỗi nghiêm trọng 2, (130 = 128 + 2, xem ở trên) ') – Dorian

3

Tôi đang sử dụng ensure để có hiệu quả tuyệt vời! Đây là những điều bạn muốn xảy ra khi nội dung của bạn kết thúc bất kể tại sao nó kết thúc.

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