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

时间:2017-12-29 16:27:11

标签: ruby command-line argv

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

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

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

或错误处理......

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

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

2 个答案:

答案 0 :(得分:1)

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

考虑到这一点,使用方法ARGF.eof?Link to documentation

答案 1 :(得分:0)

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

用法:(来自Kernel#at_exit Docs

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的终结器等待直到退出,因为它在整个应用程序中保留了它的引用。