将命令行参数解析为通配符

我写了一个简单的脚本,将所有给定的参数写入单个文本文件,由换行符分隔。 我想使用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/*'