使用ARGF在Ruby脚本中捕获Ctrl-D

我目前正在使用ARGV.gets从命令行捕获用户输入。 我想允许Ctrl-D终止脚本,但不知道如何使用Signal.trap或通过error handling来完成此操作。 我试图找到像Ctrl-D这样的陷阱代码列表,但无法找到我想要的东西。 同样,抢救Exception不起作用,因为Ctrl-D不会引发exception。 是否有Ctrl-D的陷阱代码或任何其他方式来检测这个?

例如……我目前能够通过捕获来检测Ctrl-C …

# Trap ^C Signal.trap("INT") { # Do something exit } 

或error handling……

 def get_input input = ARGF.gets input.strip! rescue SystemExit, Interrupt => e # If we get here, Ctrl-C was encountered end 

但是,我无法捕获或检测Ctrl-D。

ARGF只是流的一个特例。 Ctrl + D只是输入的结束。

考虑到这一点,使用方法ARGF.eof? 。 链接到文档

我不确定你的用例,但我假设你打算在脚本退出之前做一些事情。 如果是这样,那么你最好的选择可能比信号陷阱更容易。 Kernel Module实际上为您提供了一个#at_exit方法,该方法将在程序实际退出之前执行。

用法:(来自Kernel#at_exit文档 )

 def do_at_exit(str1) at_exit { print str1 } end at_exit { puts "cruel world" } do_at_exit("goodbye ") exit 

“生产”

 goodbye cruel world 

如您所见,您可以定义多个处理程序,这些处理程序将在程序退出时以相反的顺序执行。

由于Kernel包含在Object您也可以处理Object特性

 class People at_exit {puts "The #{self.name} have left"} end exit # The People have left 

甚至是实例

 p = People.new p.send(:at_exit, &->{puts "We are leaving"}) # We are leaving # The People have left 

此外,对于更具体的基于Object的实现,您可以查看ObjectSpace.define_finalizer

用法示例:

 class Person def self.finalize(name) proc {puts "Goodbye Cruel World -#{name}"} end def initialize(name) @name = name ObjectSpace.define_finalizer(self, self.class.finalize(@name)) end end 

用法:

 p = Person.new("engineersmnky") exit # Goodbye Cruel World -engineersmnky 

这可能不是你想要的特别之处,因为当Object被垃圾收集时也会触发(对于短暂的对象来说不是很好),但是如果你有整个应用程序中应该存在的对象,那么仍然可以使用类似于at_exit的对象。 例

 # requiring WeakRef to allow garbage collection # See: https://ruby-doc.org/stdlib-2.3.3/libdoc/weakref/rdoc/WeakRef.html require 'weakref' # p1 = Person.new("Engineer") p2 = Person.new("Engineer's Monkey") p2 = WeakRef.new(p2) GC.start # just for this example # Goodbye Cruel World -Engineer's Monkey #=> nil p2 #=> WeakRef::RefError: Invalid Reference - probably recycled exit # Goodbye Cruel World -Engineer 

正如你所看到的那样定义了p2终结器,因为Person是gc’d但程序还没有退出。 p1的终结器一直等到退出,因为它在整个应用程序中保留了它的引用。