真正便宜的命令行选项在Ruby中解析

Cur*_*son 114 ruby

编辑:请,,阅读前回答这个帖子的底部列出的两个要求.人们不断发布他们的新宝石和图书馆等等,这显然不符合要求.

有时我想非常便宜地将一些命令行选项破解成一个简单的脚本.一个有趣的方法,没有处理getopts或解析或类似的东西,是:

...
$quiet       = ARGV.delete('-d')
$interactive = ARGV.delete('-i')
...
# Deal with ARGV as usual here, maybe using ARGF or whatever.
Run Code Online (Sandbox Code Playgroud)

它不是普通的Unix选项语法,因为它将接受选项非选项命令行参数,如" myprog -i foo bar -q",但我可以忍受.(有些人,比如Subversion的开发人员,更喜欢这个.有时我也会这样做.)

只是存在或不存在的选项不能比上述更简单地实现.(一个赋值,一个函数调用,一个副作用.)是否有一种同样简单的方法来处理带参数的选项,例如" -f filename "?

编辑:

我之前没有说过的一点,因为直到Trollop的作者提到图书馆符合"一个[800行]文件"之前我才清楚,我的目的不仅仅是清洁语法,但对于具有以下特征的技术:

  1. 整个代码可以包含在脚本文件中(不会压倒实际的脚本本身,可能只有几十行),因此可以bin使用标准的Ruby 1.8在任何系统上删除dir中的单个文件.[5-7]安装并使用它.如果你不能编写一个没有require语句的Ruby脚本,并且解析几个选项的代码在十几行左右,那么你就不能满足这个要求.

  2. 代码很小而且非常简单,人们可以记住足够的代码来直接输入代码来完成这一操作,而不是从其他地方剪切和粘贴.想想你在一个没有互联网访问权限的防火墙服务器的控制台上的情况,你想把一个快速的脚本拼凑起来供客户使用.我不了解你,但是(除了上面的要求失败之外)记住甚至45行的简化微型optparse也不是我要做的事情.

小智 233

作为Trollop的作者,我无法相信人们认为在选项解析器中合理的东西.认真.它令人难以置信.

为什么我必须创建一个扩展其他模块的模块来解析选项?为什么我必须继承任何东西?为什么我只需要订阅一些"框架"来解析命令行?

这是上面的Trollop版本:

opts = Trollop::options do
  opt :quiet, "Use minimal output", :short => 'q'
  opt :interactive, "Be interactive"
  opt :filename, "File to process", :type => String
end
Run Code Online (Sandbox Code Playgroud)

就是这样.opts现在是连键的哈希:quiet,:interactive:filename.你可以用它做任何你想做的事.你会得到一个漂亮的帮助页面,格式适合你的屏幕宽度,自动短参数名称,类型检查......你需要的一切.

它是一个文件,因此如果您不想要正式的依赖项,可以将它放在lib /目录中.它有一个很容易上手的最小DSL.

LOC每个选项的人.这很重要.

  • 请不要将此调低一点.兄弟,这是一个正义的熨平板. (50认同)
  • BTW,+1已经写过Trollop(这里已经提到过了),但是可以随意淡化第一段. (38认同)
  • 在这种情况下,他有权抱怨我害怕.当你看看替代方案:[[1](http://rubyforge.org/docman/view.php/632/233/posted-docs.index.html)] [[2](http:// ruby​​- doc.org/core/classes/OptionParser.html)] [[3](http://ruby-doc.org/core/classes/GetoptLong.html)],基本上只处理一个简单的字符串数组(no真的,让它沉入其中,你不禁想知道为什么?你从这一切膨胀中获得了什么?这不是C,其中字符串是"有问题的".当然每个人都有自己的.:) (32认同)
  • 随意点一下第十个单词. (6认同)
  • Trollop +1.我将它用于我的测试自动化系统并且Just Works.此外,它很容易编码,有时我重新排列我的横幅只是为了体验它的乐趣. (3认同)

ram*_*ion 76

我分享你的厌恶require 'getopts',主要是因为这是令人敬畏的OptionParser:

% cat temp.rb                                                            
require 'optparse'
OptionParser.new do |o|
  o.on('-d') { |b| $quiet = b }
  o.on('-i') { |b| $interactive = b }
  o.on('-f FILENAME') { |filename| $filename = filename }
  o.on('-h') { puts o; exit }
  o.parse!
end
p :quiet => $quiet, :interactive => $interactive, :filename => $filename
% ruby temp.rb                                                           
{:interactive=>nil, :filename=>nil, :quiet=>nil}
% ruby temp.rb -h                                                        
Usage: temp [options]
    -d
    -i
    -f FILENAME
    -h
% ruby temp.rb -d                                                        
{:interactive=>nil, :filename=>nil, :quiet=>true}
% ruby temp.rb -i                                                        
{:interactive=>true, :filename=>nil, :quiet=>nil}
% ruby temp.rb -di                                                       
{:interactive=>true, :filename=>nil, :quiet=>true}
% ruby temp.rb -dif apelad                                               
{:interactive=>true, :filename=>"apelad", :quiet=>true}
% ruby temp.rb -f apelad -i                                              
{:interactive=>true, :filename=>"apelad", :quiet=>nil}
Run Code Online (Sandbox Code Playgroud)

  • 谢谢,我无法看到这不符合OP的请求,特别是考虑到它在标准库中的全部,与安装/出售任何非标准代码的需要相比 (6认同)
  • 这看起来就像trollop版本,除了它不需要额外的文件. (3认同)

Cur*_*son 59

这是我经常使用的标准技术:

#!/usr/bin/env ruby

def usage(s)
    $stderr.puts(s)
    $stderr.puts("Usage: #{File.basename($0)}: [-l <logfile] [-q] file ...")
    exit(2)
end

$quiet   = false
$logfile = nil

loop { case ARGV[0]
    when '-q' then  ARGV.shift; $quiet = true
    when '-l' then  ARGV.shift; $logfile = ARGV.shift
    when /^-/ then  usage("Unknown option: #{ARGV[0].inspect}")
    else break
end; }

# Program carries on here.
puts("quiet: #{$quiet} logfile: #{$logfile.inspect} args: #{ARGV.inspect}")
Run Code Online (Sandbox Code Playgroud)

  • +*实际上*回答问题:) (13认同)
  • 预制车轮不平滑.仔细阅读问题,仔细注意要求. (7认同)
  • 回答这个问题,但男人,Trollop似乎要容易处理.为什么在预制车轮更加平滑的情况下重新发明轮子? (3认同)
  • +1有时你需要重新发明轮子,因为你不想或只是*不能*使用像Trollop这样的其他依赖. (2认同)

bjj*_*jjb 34

既然没有人提到它,并且标题确实是指廉价的命令行解析,为什么不让红宝石翻译为你做这项工作呢?如果您通过-s开关(例如,在您的shebang中),您可以免费获得污垢简单开关,分配给单字母全局变量.以下是使用该开关的示例:

#!/usr/bin/env ruby -s
puts "#$0: Quiet=#$q Interactive=#$i, ARGV=#{ARGV.inspect}"
Run Code Online (Sandbox Code Playgroud)

这是我保存为./test和chmod它的输出+x:

$ ./test
./test: Quiet= Interactive=, ARGV=[]
$ ./test -q foo
./test: Quiet=true Interactive=, ARGV=["foo"]
$ ./test -q -i foo bar baz
./test: Quiet=true Interactive=true, ARGV=["foo", "bar", "baz"]
$ ./test -q=very foo
./test: Quiet=very Interactive=, ARGV=["foo"]
Run Code Online (Sandbox Code Playgroud)

详情ruby -h请见.:)

必须和它一样便宜.如果你尝试像-:这样的开关,它会引发一个NameError ,所以那里有一些验证.当然,在非切换参数之后你不能有任何开关,但如果你需要一些花哨的东西,你真的应该在最小的OptionParser上使用.事实上,唯一令我烦恼的是这种技术,当你访问一个未设置的全局变量时,你会得到一个警告(如果你已经启用它们),但它仍然是假的,所以它适用于一次性工具和快速脚本.

一个警告(正如FelipeC在评论中指出的那样)是你的shell可能不支持3-token shebang; 您可能需要替换/usr/bin/env ruby -wruby的实际路径(如/usr/local/bin/ruby -w),或者从包装脚本或其他东西运行它.

  • 在过去的两年里,我确实一直在等待这个答案.:-)更严重的是,这是我正在寻找的那种聪明的想法.警告的事情有点烦人,但我可以想办法减轻这种情况. (3认同)
  • 谢谢:)我当然希望他过去两年没有等待这个答案. (2认同)

Flo*_*ilz 13

我构建了micro-optparse,以填补这个简短但易于使用的选项解析器的明显需求.它的语法类似于Trollop,短70行.如果您不需要验证而且没有空行,则可以将其减少到45行.我认为这正是你所寻找的.

简短的例子:

options = Parser.new do |p|
  p.version = "fancy script version 1.0"
  p.option :verbose, "turn on verbose mode"
  p.option :number_of_chairs, "defines how many chairs are in the classroom", :default => 1
  p.option :room_number, "select room number", :default => 2, :value_in_set => [1,2,3,4]
end.process!
Run Code Online (Sandbox Code Playgroud)

-h--help打印脚本调用脚本

Usage: micro-optparse-example [options]
    -v, --[no-]verbose               turn on verbose mode
    -n, --number-of-chairs 1         defines how many chairs are in the classroom
    -r, --room-number 2              select room number
    -h, --help                       Show this message
    -V, --version                    Print version
Run Code Online (Sandbox Code Playgroud)

它检查输入是否与默认值类型相同,生成短访问器和长访问器,如果给出无效参数则打印描述性错误消息等等.

我通过使用每个选项解析器来解决我遇到的问题,比较了几个选项解析器.您可以使用这些示例和我的摘要做出信息性决策.随意添加更多实现到列表中.:)

  • 比较行计数是绝对可以的,因为`optparse`是一个默认库,即它随每个ruby安装一起提供.`Trollop`是第三方库,因此每次要将其包含在项目中时都必须导入完整的代码.μ-optparse总是只需要~70行,因为`optparse`已经存在. (6认同)

Pet*_*per 8

我完全理解为什么你要避免optparse - 它可能会得到太多.但是有一些远远"轻松"的解决方案(与OptParse相比)作为库来实现,但它足够简单,可以使单个宝石安装变得有价值.

例如,查看此OptiFlag示例.只需几行处理.根据您的情况量身定制的略微截断的示例:

require 'optiflag'

module Whatever extend OptiFlagSet
  flag "f"
  and_process!
end 

ARGV.flags.f # => .. whatever ..
Run Code Online (Sandbox Code Playgroud)

还有很多定制的例子.我记得使用另一个更容易,但它现在已经逃脱了我,但如果我找到它,我会回来在这里添加评论.