Во-первых, оболочка1 выдает одинаковое конечное значение для всех следующих вариантов кавычек:
./scrit.rb -t 'foo,bar',baz
./scrit.rb -t foo,'bar,baz'
./scrit.rb -t 'foo,bar,baz'
./scrit.rb -t foo,bar,baz
./scrit.rb -t fo"o,b"ar,baz
./scrit.rb -t foo,b\ar,baz
# obviously many more variations are possible
Вы можете проверить это так:
ruby -e 'f=ARGV[0];ARGV.each_with_index{|a,i|puts "%u: %s <%s>\n" % [i,a==f,a]}'\
'foo,bar',baz foo,'bar,baz' 'foo,bar,baz' foo,bar,baz fo"o,b"ar,baz foo,b\ar,baz
1 Я предполагаю, что оболочка похожа на Bourne (некоторые варианты sh, такие как zsh, bash, ksh, тире и т. д.).
Если вы хотите переключиться на другой разделитель, вы можете сделать это следующим образом:
split_on_semicolons = Object.new
OptionParser.accept split_on_semicolons do |s,|
s.split ';'
end
⋮
opts.on('-t', '--thing [THING1;THING2]', split_on_semicolons, 'Set THING1, THING2 (semicolon must be quoted to protect it from the shell)') do |t|
options[:things] = t
end
Оболочка придает особое значение точке с запятой, поэтому она должна быть экранирована или заключена в кавычки (иначе она служит безусловным разделителем команд (например, echo foo; sleep 2; echo bar
)):
./scrit.rb -t foo,bar\;baz
./scrit.rb -t foo,bar';'baz
./scrit.rb -t 'foo,bar;baz'
# et cetera
«Синтаксический анализ», выполняемый при указании Array
, почти в точности аналогичен базовому str.split(',')
(он также отбрасывает пустые строковые значения), поэтому нет возможности напрямую указать escape-символ.
Если вы хотите придерживаться запятых, но ввести «экранирующий символ», то вы можете немного обработать значения в своем блоке OptionParser#on
, чтобы сшить определенные значения обратно вместе:
# use backslash as an after-the-fact escape character
# in a sequence of string values,
# if a value ends with a odd number of backslashes, then
# the last backslash should be replaced with
# a command concatenated with the next value
# a backslash before any other single character is removed
#
# basic unsplit: (note doubled backslashes due to writing these as Ruby values)
# %w[foo\\ bar baz] => %w[foo,bar baz]
#
# escaped, trailing backslash is not an unsplit:
# %w[foo\\\\ bar baz] => %w[foo\\ bar baz]
#
# escaping [other, backslash, split], also consecutive unsplits
# %w[f\\o\\\\o\\ \\\\\\bar\\\\\\ baz] => %w[fo\\o,\\bar\\,baz]
def unsplit_and_unescape(orig_values)
values = []
incompleteValue = nil
orig_values.each do |val|
incomplete = /\\*$/.match(val)[0].length.odd?
val.gsub! /\\(.)/, '\1'
val = incompleteValue + ',' + val if incompleteValue
if incomplete
incompleteValue = val[0..-2]
else
values << val
incompleteValue = nil
end
end
if incompleteValue
raise ArgumentError, 'Incomplete final value'
end
values
end
⋮
opts.on('-t', '--thing [THING1,THING2]', Array, 'Set THING1, THING2 (use \\, to include a comma)') do |t|
options[:things] = unsplit_and_unescape(t)
end
Затем вы можете запустить его из оболочки следующим образом (обратная косая черта также является специальной для оболочки, поэтому ее необходимо экранировать или заключить в кавычки2):
./scrit.rb -t foo\\,bar,baz
./scrit.rb -t 'foo\,bar,baz'
./scrit.rb -t foo'\,'bar,baz
./scrit.rb -t "foo\\,bar,baz"
./scrit.rb -t fo"o\\,ba"r,baz
# et cetera
2 В отличие от Ruby, одинарная кавычка оболочки полностью буквальна (например, обратная косая черта не интерпретируется), поэтому часто это хороший выбор, когда вам нужно встроить любую другую оболочку. специальные символы (такие как обратная косая черта и двойные кавычки).
person
Chris Johnsen
schedule
20.07.2011