2

我编写了一个简单的脚本,将所有给定的参数写入单个文本文件,用换行符分隔。我想使用 OptionParser 将文件列表传递给它。我想使用通配符添加几个文件,例如/dir/*.

我试过这个:

opts = OptionParser.new 
opts.on('-a', '--add FILE') do |s| 
  puts "DEBUG: before #{s}"
  @options.add = s
  puts "DEBUG: after #{@options.add}"
end
...
def process_arguments
  @lines_to_add = Dir.glob @options.add
end

当我添加这样的文件时放置:

./script.rb -a /path/*

我总是只得到目录中的第一个文件。所有调试输出只显示目录的第一个文件,似乎 OptionParser 做了一些神奇的解释

有谁知道如何处理这个?

4

4 回答 4

4

您没有提到您正在使用哪个操作系统(这很重要)。

在 Windows 上,您在命令行上键入的任何内容都会未经修改地传递给程序。所以如果你输入

./script.rb -a /path/*

那么程序的参数包含"-a""/path/*"

在 Unix 和其他具有类似 shell 的系统上,shell 会自动扩展命令行中的通配符的参数扩展。因此,当您在上面键入相同的命令时,shell会查找/path/*目录中的文件并在程序运行之前展开命令行参数。所以你的程序的参数可能是"-a","/path/file1""/path/file2".

重要的一点是,脚本无法确定参数扩展是否发生,或者用户是否真的在命令行上输入了所有这些文件名。

于 2010-10-17T19:03:03.020 回答
3

如上所述,命令行在操作系统将命令交给 Ruby 之前被解析。通配符正在扩展为以空格分隔的文件名列表。

您可以看到如果您echo *在命令行键入类似的内容会发生什么,然后,而不是点击Return,而是点击Escthen *。您应该会看到*扩展的匹配文件列表。

击中Return这些名称后,将被添加到 ARGV 数组中。OptionParser 将遍历 ARGV 并找到您定义的标志,如有必要,获取以下元素,然后将它们从 ARGV 中删除。当 OptionParser 完成时,任何不适合选项的 ARGV 元素将保留在 ARGV 数组中,您可以在其中获取它们。

在您的代码中,您正在寻找'-a'or'--add FILE'选项的单个参数。OptionParser 有一个Array选项,它将从命令行获取逗号分隔的元素,但随后将使用空格分隔的元素。

require 'optparse'

options = []
opts = OptionParser.new 
opts.on('-a', '--add FILE', Array) do |s| 
  options << s
end.parse!

print "options => ", options.join(', '), "\n"
print "ARGV => ",    ARGV.join(', '),    "\n"

将其保存到文件并尝试使用命令行-a one two three,然后使用-a one,two,three. 您将看到该Array选项如何根据参数之间是否有逗号或空格以不同方式抓取元素。

因为*通配符被替换为空格分隔的文件名,所以您必须在 OptionParser 对它运行后对 ARGV 进行后处理,或者以编程方式全局化目录并以这种方式构建列表。ARGV 拥有除选项中选择的文件之外的所有文件,-a因此,就我个人而言,我会放弃该-a选项并让 ARGV 包含所有文件。

*如果文件太多并且超出缓冲区大小,您将不得不对目录进行全局化。您会知道是否会发生这种情况,因为操作系统会抱怨。

于 2010-10-17T23:37:59.337 回答
0

发生的事情是,在 Ruby 使用通配符之前,shell 正在扩展通配符。所以你真的在处理:

./script.rb -a /path/file1 /path/file2 ......

加上引号/path/*以避免 shell 扩展并将通配符传递给 Ruby:

./script.rb -a '/path/*'
于 2010-10-17T19:02:55.473 回答
0

Shell 在将参数传递给您的程序之前对其进行扩展。要么继续使用文件名,直到找到另一个选项,要么让用户转义通配符(例如./script.rb -a '/path/*')并自己将它们全局化。

于 2010-10-17T19:03:05.953 回答