我写了一个简单的脚本,它将所有给定的参数写入单个文本文件,由换行符分隔。我想使用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做了一些神奇的解释
有谁知道如何处理这个问题?
答案 0 :(得分:4)
您没有提到您正在使用的操作系统(这很重要)。
在Windows上,无论您在命令行上键入什么,都会传递给程序而不进行修改。所以,如果你输入
./script.rb -a /path/*
然后该程序的参数包含"-a"
和"/path/*"
。
在Unix和其他具有类似shell的系统上,shell执行参数扩展,它会自动扩展命令行中的通配符。因此,当您在上面键入相同的命令时, shell 会查找/path/*
目录中的文件,并在程序运行之前展开命令行参数。因此,您的计划的参数可能是"-a"
,"/path/file1"
和"/path/file2"
。
重要的一点是,脚本无法确定参数扩展是否发生,或者用户是否在命令行中实际输入了所有这些文件名。
答案 1 :(得分:3)
如上所述,在操作系统将命令交给Ruby之前,正在解析命令行。通配符正在扩展为以空格分隔的文件名列表。
你可以看到如果在命令行输入类似echo *
的内容会发生什么,然后不是点击返回,而是点击 Esc 然后 * 。您应该看到*
已扩展到匹配文件列表中。
点击返回后,这些名称将被添加到ARGV数组中。 OptionParser将遍历ARGV并找到您定义的标志,必要时抓取以下元素,然后从ARGV中删除它们。当OptionParser完成时,任何不适合选项的ARGV元素将保留在ARGV数组中,您可以在其中获取它们。
在您的代码中,您正在为'-a'
或'--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包含所有文件。
如果*
包含太多文件且超出缓冲区大小,则必须对目录进行全局操作。你会知道是否会发生这种情况,因为操作系统会抱怨。
答案 2 :(得分:0)
正在发生的事情是shell在Ruby到达之前扩展了通配符。所以你真正在处理:
./script.rb -a /path/file1 /path/file2 ......
在/path/*
周围加上引号以避免shell扩展并将通配符传递给Ruby:
./script.rb -a '/path/*'
答案 3 :(得分:0)
shell在将参数传递给程序之前将其展开。要么继续使用文件名,直到找到另一个选项,要么让用户转义通配符(例如./script.rb -a '/path/*'
)并自己将它们全局化。