Parsing command-line arguments as wildcards

非 Y 不嫁゛ 提交于 2019-11-30 19:34:27

问题


I wrote a simple script that writes all given arguments to a single text file, separated by newline. I'd like to pass a list of files to it using OptionParser. I would like to add a couple of files using wildcards like /dir/*.

I tried this:

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

Put when I add files like this:

./script.rb -a /path/*

I always get only the first file in the directory. All the debug outputs show only the first file of directory, and it seems as if OptionParser does some magic interpretations

Does anyone know how to handle this?


回答1:


You didn't mention which operating system you are using (it matters).

On Windows, whatever you type on the command line gets passed to the program without modification. So if you type

./script.rb -a /path/*

then the arguments to the program contain "-a" and "/path/*".

On Unix and other systems with similar shells, the shell does argument expansion that automatically expands wildcards in the command line. So when you type the same command above, the shell looks to find the files in the /path/* directory and expands the command line arguments before your program runs. So the arguments to your program might be "-a", "/path/file1", and "/path/file2".

An important point is that the script cannot find out whether argument expansion happened, or whether the user actually typed all those filenames out on the command line.




回答2:


As mentioned above, the command-line is being parsed before the OS hands off the command to Ruby. The wildcard is being expanded into a list of space-delimited filenames.

You can see what will happen if you type something like echo * at the command-line, then, instead of hitting Return, instead hit Esc then *. You should see the * expanded into the list of matching files.

After hitting Return those names will be added to the ARGV array. OptionParser will walk through ARGV and find the flags you defined, grab the following elements if necessary, then remove them from ARGV. When OptionParser is finished any ARGV elements that didn't fit into the options will remain in the ARGV array where you can get at them.

In your code, you are looking for a single parameter for the '-a' or '--add FILE' option. OptionParser has an Array option which will grab comma-separated elements from the command line but will subsequent space-delimited ones.

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"

Save that to a file and try your command line with -a one two three, then with -a one,two,three. You'll see how the Array option grabs the elements differently depending on whether there are commas or spaces between the parameters.

Because the * wildcard gets replaced with space delimited filenames you'll have to post-process ARGV after OptionParser has run against it, or programmatically glob the directory and build the list that way. ARGV has all the files except the one picked up in the -a option so, personally, I'd drop the -a option and let ARGV contain all the files.

You will have to glob the directory if * has to too many files and exceeds the buffer size. You'll know if that happens because the OS will complain.




回答3:


The shell is expanding the argument before it gets passed to your program. Either keep consuming filenames until you reach another option, or have the user escape the wildcards (e.g. ./script.rb -a '/path/*') and glob them yourself.




回答4:


What's happening is the shell is expanding the wildcard before Ruby gets to it. So really you are processing:

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

Put quotes around /path/* to avoid the shell expansion and pass the wildcard to Ruby:

./script.rb -a '/path/*'


来源:https://stackoverflow.com/questions/3954750/parsing-command-line-arguments-as-wildcards

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!