Синтаксический анализ аргументов командной строки - PullRequest
2 голосов
/ 17 октября 2010

Я написал простой скрипт, который записывает все заданные аргументы в один текстовый файл, разделенный новой строкой. Я хотел бы передать ему список файлов с помощью 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 голосов
/ 17 октября 2010

Вы не упомянули, какую операционную систему вы используете (это имеет значение).

В Windows все, что вы вводите в командной строке, передается программе без изменений.Поэтому, если вы наберете

./script.rb -a /path/*

, то аргументы программы будут содержать "-a" и "/path/*".

. В Unix и других системах с похожими оболочками оболочка делает аргумент расширение , которое автоматически расширяет символы подстановки в командной строке.Поэтому, когда вы вводите ту же команду выше, shell ищет файлы в каталоге /path/* и расширяет аргументы командной строки перед запуском вашей программы.Таким образом, аргументы вашей программы могут быть "-a", "/path/file1" и "/path/file2".

Важным моментом является то, что сценарий не может определить, произошло ли расширение аргумента или пользователь действительно набрал все эти символы.имена файлов в командной строке.

3 голосов
/ 18 октября 2010

Как уже упоминалось выше, командная строка анализируется перед тем, как ОС передает команду Ruby. Подстановочный знак расширяется до списка имен файлов, разделенных пробелами.

Вы можете увидеть, что произойдет, если вы наберете что-то вроде echo * в командной строке, тогда вместо нажатия Return вместо нажатия 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 по-разному захватывает элементы в зависимости от того, есть ли запятые или пробелы между параметрами.

Поскольку подстановочный знак * заменяется именами файлов, разделенными пробелами, вам придется постобработать ARGV после того, как OptionParser запустит его, или программно перелистать каталог и построить список таким образом. У ARGV есть все файлы, кроме файла, выбранного в опции -a, так что лично я бы выбрал опцию -a и позволил ARGV содержать все файлы.

Вам придется создать глобальную директорию, если * имеет слишком много файлов и превышает размер буфера. Вы узнаете, если это произойдет, потому что ОС будет жаловаться.

0 голосов
/ 17 октября 2010

Оболочка расширяет аргумент, прежде чем он будет передан вашей программе.Либо продолжайте использовать имена файлов, пока не дойдете до другого варианта, либо попросите пользователя экранировать символы подстановки (например, ./script.rb -a '/path/*') и сделать их самостоятельно.

0 голосов
/ 17 октября 2010

То, что происходит, - оболочка расширяет шаблон, прежде чем Руби доберется до него. Так что на самом деле вы обрабатываете:

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

Поместите кавычки вокруг /path/*, чтобы избежать расширения оболочки и передайте шаблон Ruby:

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