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