0

我正在使用 Ruby 执行带有命令行参数的代码。现在我尝试使用具有不同选项的同一程序,因此我将选项放在一个文件中,并且我希望程序读取每一行解释选项并相应地执行程序。

但我得到这个错误。"C:/Ruby193/lib/ruby/1.9.1/optparse.rb:1348:in block in parse_in_order': undefined methodshift' for "--c execue --query unix --Servername abc123":String (NoMethodError)"

我知道它读取文件并将该行视为字符串。但想知道是否有办法克服这个移位错误并将该行视为在命令提示符中输入。或任何更好的解决方案。

这是我的代码。

require 'optparse'
require 'micro-optparse'
# --command execue --query unix command --Servername abc123
f =File.open("list_of_commands.txt", "r")
f.each_line { |line| 
line= line.chomp
#line = "--c execue --query unix --Servername abc123"
#line = eval("\"#{line}\"")
puts line

 options = {}
OptionParser.new do |opts|

  opts.on("-c", "--command result,execue,chart,scpfile", String, "Single command to execute ") do |c|
    options[:comd] = c
  end

  opts.on("-q", "--query remote command, unix command", String, "performs the command on local or remote machine") do |q|
    options[:query] = q
  end

  opts.on("-s", "--servername CHSXEDWDC002 ", String, "server name to execute the command") do |v|
    options[:hname] = v
  end

    opts.on_tail('-h', '--help', 'Show this message') do
    puts opts
     exit
   end

 end.parse!(line)
 p options
 }

该文件的内容如下 --c execue --query unix --Servername abc123

我也尝试使用 micro-optparse 但面临同样的错误。任何解决方法?

更新: 根据“@mu 太短”的建议,我尝试了以下选项。end.parse!("#{Shellwords.shellsplit(line)}") 和/或 end.parse!(Shellwords.shellsplit(line))。但他们都没有工作。

我还尝试使用“line = line.split("\t")" 将行拆分为数组,然后使用 end.parse!(line)。输出为 --c execue --query unix --Servername abc123

但现在我收到错误作为阻止:无效选项--c执行

更新:#2 查看错误,问题在于错误的参数(-c。但感谢用户“@mu 太短”建议使用 Array.

更新: 3 传递数组仅适用于短格式的参数,例如 -c,但是当提供长格式时,它会因无效参数错误而失败。

我没有看到关于 optparse 的太多文档。我什至尝试过微解析,但它需要默认值,这对我来说不是一个选项:(

4

2 回答 2

2

虽然您可以将命令行参数放入文件、标志和所有内容中,但还有更好的方法来记住配置设置。

不要存储标志,而是使用YAML文件。YAML 是一种出色的数据格式,可以轻松转换为 Ruby 哈希和对象。“ Yaml Cookbook ”是一个非常有用的页面,用于学习 Ruby 格式的来龙去脉。有无数其他语言的 YAML 解析器,可以轻松共享设置,随着系统的增长,这可能会很有用。

使用一些创意代码,您可以使用 YAML 作为基本设置,并让 CLI 标志覆盖存储的设置。

如果您不熟悉 YAML,可以使用以下内容轻松开始文件:

require 'yaml'

data = {
  'command' => %w[result execute chart scpfile],
  'query' => ['remote command', 'unix command'],
  'servername' => 'CHSXEDWHDC002',
}

puts data.to_yaml

哪个输出:

---
command:
- result
- execute
- chart
- scpfile
query:
- remote command
- unix command
servername: CHSXEDWHDC002

将该输出重定向到以 结尾的文件,.yaml然后您就可以使用了。

要将其读回脚本中,请使用:

require 'yaml'

data = YAML.load_file('path/to/data.yaml')

快速往返测试显示:

require 'yaml'

data = {
  'command' => %w[result execute chart scpfile],
  'query' => ['remote command', 'unix command'],
  'servername' => 'CHSXEDWHDC002',
}

YAML.load(data.to_yaml)

看起来像:

{"command"=>["result", "execute", "chart", "scpfile"],
"query"=>["remote command", "unix command"],
"servername"=>"CHSXEDWHDC002"}

如果您想将默认值存储在 YAML 文件中,并用命令行标志覆盖它们,请从文件中读取数据,然后使用该结果对象作为 OptionParse 的基础:

require 'optparse'
require 'yaml'

# Note, YAML can deal with symbols as keys, but other languages might not like them.
options = {
  :comd => %w[result execute chart scpfile],
  :query => ['remote command', 'unix command'],
  :hname => 'CHSXEDWHDC002',
}

# we'll overwrite the options variable to pretend we loaded it from a file.
options = YAML.load(options.to_yaml)

OptionParser.new do |opts|

  opts.on("-c", "--Command result,execue,chart,scpfile", String, "Single command to execute ") do |c|
    options[:comd] = c
  end

  opts.on("-q", "--query remote command, unix command", String, "performs the command on local or remote machine") do |q|
    options[:query] = q
  end

  opts.on("-s", "--Servername CHSXEDWHDC002 ", String, "server name to execute the command") do |v|
    options[:hname] = v
  end

  opts.on_tail('-h', '--help', 'Show this message') do
    puts opts
    exit
  end

end.parse!

这没有经过测试,但我们一直在工作中做类似的事情,所以把它保存到一个文件中,然后用一根棍子戳它一会儿,看看你想出了什么。

于 2013-04-25T03:34:02.813 回答
2

parse!方法需要一个数组作为其参数,而不是字符串。您可能希望使用Shellwords.shellsplit而不是String#split(或类似的手动方法)将您的转换line为数组,以防万一您必须处理引用和诸如此类的事情。像这样的东西:

OptionParser.new do |opts|
  #...
end.parse!(Shellwords.shellsplit(line))
于 2013-04-24T22:00:43.240 回答