PYTHON 带有可选和强制参数的命令的所有可能性
PYTHON all possibilities of command with optional and mandatory parameters
我正在与一些在 python 中列出带有可选和强制参数的命令的所有可能性进行斗争。我需要它根据某些脚本的帮助输出在 bash 中生成一些自动完成脚本。
例如虚构命令:
add disk -pool <name> { -diskid <diskid> | -diskid auto [-fx | -tdr] } [-fx] [-status { enable | disable } ]
其中:{} 必填,[] 可选,|或
上述命令的所有 (24) 种可能性的预期结果:
add disk -pool <name> -diskid <diskid>
add disk -pool <name> -diskid <diskid> -capacity_saving
add disk -pool <name> -diskid <diskid> -capacity_saving -status enable
add disk -pool <name> -diskid <diskid> -capacity_saving -status disable
add disk -pool <name> -diskid <diskid> -status enable
add disk -pool <name> -diskid <diskid> -status disable
add disk -pool <name> -diskid auto
add disk -pool <name> -diskid auto -capacity_saving
add disk -pool <name> -diskid auto -capacity_saving -status enable
add disk -pool <name> -diskid auto -capacity_saving -status disable
add disk -pool <name> -diskid auto -status enable
add disk -pool <name> -diskid auto -status disable
add disk -pool <name> -diskid auto -fx
add disk -pool <name> -diskid auto -fx -capacity_saving
add disk -pool <name> -diskid auto -fx -capacity_saving -status enable
add disk -pool <name> -diskid auto -fx -capacity_saving -status disable
add disk -pool <name> -diskid auto -fx -status enable
add disk -pool <name> -diskid auto -fx -status disable
add disk -pool <name> -diskid auto -tdr
add disk -pool <name> -diskid auto -tdr -capacity_saving
add disk -pool <name> -diskid auto -tdr -capacity_saving -status enable
add disk -pool <name> -diskid auto -tdr -capacity_saving -status disable
add disk -pool <name> -diskid auto -tdr -status enable
add disk -pool <name> -diskid auto -tdr -status disable
我试过 import intertool
+ product()
但它只适用于不太复杂的命令,如 { -diskid <diskid> | -diskid auto }
所以如果括号中没有更多的括号,如下面的命令输出:
# add disk -pool <name> { -diskid <diskid> | -diskid auto } [-fx]
command = [ ['add'], ['disk'], ['-pool <name>'], ['-diskid <diskid>', '-diskid auto'], ['', '-fx']]
print(list(itertools.product(*command)))
print(len(list(itertools.product(*command))))
输出:
[('add', 'disk', '-pool <name>', '-diskid <diskid>', ''),
('add', 'disk', '-pool <name>', '-diskid <diskid>', '-fx'),
('add', 'disk', '-pool <name>', '-diskid auto', ''),
('add', 'disk', '-pool <name>', '-diskid auto', '-fx')]
4
怎样才能得到预期的结果? :c
您为虚构命令提供的语法与预期输出不匹配(例如 -capacity_saving
)。
尽管如此 :
import itertools
# OP syntax :
# add disk -pool <name> { -diskid <diskid> | -diskid auto [-fx | -tdr] } [-fx] [-status { enable | disable } ]
command = (
# one mandatory diskid
("-diskid <diskid>", "-diskid auto", "-diskid auto -fx", "-diskid auto -tdr"),
# one optional fx
(None, "-fx"),
# one optional status
(None, "-status enable", "-status disable")
)
prefix = "add disk -pool <name> "
all_usages = tuple(itertools.product(*command))
print("\n".join(str(prefix + tuple(filter(lambda arg: arg is not None, usage))) for usage in all_usages))
print("total:", len(all_usages))
给我
('add', 'disk', '-pool', '<name>', '-diskid <diskid>')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-fx', '-status disable')
total: 24
下面的解决方案采用了更通用的方法。首先,parse_commands
将字符串命令转换为列表和字典的嵌套对象,然后 command_combos
从 parse_commands
:
生成的对象中生成所有可能的命令组合
import re, collections itertools
s = 'add disk -pool <name> { -diskid <diskid> | -diskid auto [-fx | -tdr] } [-fx] [-status { enable | disable } ]'
symbols = {'|':None, '{':'}', '[':']'}
def parse_command(s, f = False, t = None):
#take in a string command and parse it
b = []
while s:
n = s.popleft()
if f:
if t is None and n in [*symbols, *symbols.values()]:
s.appendleft(n)
break
if t is not None and n == symbols[t]:
break
if n not in [*symbols, *symbols.values()]:
b.append(n)
elif n == '|':
b = [{'action':'or', 'blocks':(b, list(parse_command(s, f = True, t = None)))}]
else:
b.append({'action':{'{':'mandatory', '[':'optional'}[n], 'blocks':list(parse_command(s, f = True, t = n))})
yield from b
def command_combos(d, c = []):
#recursively traverse parsed command and produce combinations
if not d:
yield c
else:
if isinstance(d[0], str):
yield from command_combos(d[1:], c+[d[0]])
else:
if d[0]['action'] == 'optional':
yield from command_combos(d[1:], c)
for b in (d[0]['blocks'] if d[0]['action'] == 'or' else [d[0]['blocks']]):
for i in command_combos(b, []):
yield from command_combos(d[1:], c+i)
综合起来:
new_s = list(parse_command(collections.deque(re.findall('[\{\[\}\]\|]|\-*\<*\w+\>*', s))))
combos = list(command_combos(new_s))
输出:
[['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-fx', '-status', 'disable']]
我正在与一些在 python 中列出带有可选和强制参数的命令的所有可能性进行斗争。我需要它根据某些脚本的帮助输出在 bash 中生成一些自动完成脚本。
例如虚构命令:
add disk -pool <name> { -diskid <diskid> | -diskid auto [-fx | -tdr] } [-fx] [-status { enable | disable } ]
其中:{} 必填,[] 可选,|或
上述命令的所有 (24) 种可能性的预期结果:
add disk -pool <name> -diskid <diskid>
add disk -pool <name> -diskid <diskid> -capacity_saving
add disk -pool <name> -diskid <diskid> -capacity_saving -status enable
add disk -pool <name> -diskid <diskid> -capacity_saving -status disable
add disk -pool <name> -diskid <diskid> -status enable
add disk -pool <name> -diskid <diskid> -status disable
add disk -pool <name> -diskid auto
add disk -pool <name> -diskid auto -capacity_saving
add disk -pool <name> -diskid auto -capacity_saving -status enable
add disk -pool <name> -diskid auto -capacity_saving -status disable
add disk -pool <name> -diskid auto -status enable
add disk -pool <name> -diskid auto -status disable
add disk -pool <name> -diskid auto -fx
add disk -pool <name> -diskid auto -fx -capacity_saving
add disk -pool <name> -diskid auto -fx -capacity_saving -status enable
add disk -pool <name> -diskid auto -fx -capacity_saving -status disable
add disk -pool <name> -diskid auto -fx -status enable
add disk -pool <name> -diskid auto -fx -status disable
add disk -pool <name> -diskid auto -tdr
add disk -pool <name> -diskid auto -tdr -capacity_saving
add disk -pool <name> -diskid auto -tdr -capacity_saving -status enable
add disk -pool <name> -diskid auto -tdr -capacity_saving -status disable
add disk -pool <name> -diskid auto -tdr -status enable
add disk -pool <name> -diskid auto -tdr -status disable
我试过 import intertool
+ product()
但它只适用于不太复杂的命令,如 { -diskid <diskid> | -diskid auto }
所以如果括号中没有更多的括号,如下面的命令输出:
# add disk -pool <name> { -diskid <diskid> | -diskid auto } [-fx]
command = [ ['add'], ['disk'], ['-pool <name>'], ['-diskid <diskid>', '-diskid auto'], ['', '-fx']]
print(list(itertools.product(*command)))
print(len(list(itertools.product(*command))))
输出:
[('add', 'disk', '-pool <name>', '-diskid <diskid>', ''),
('add', 'disk', '-pool <name>', '-diskid <diskid>', '-fx'),
('add', 'disk', '-pool <name>', '-diskid auto', ''),
('add', 'disk', '-pool <name>', '-diskid auto', '-fx')]
4
怎样才能得到预期的结果? :c
您为虚构命令提供的语法与预期输出不匹配(例如 -capacity_saving
)。
尽管如此 :
import itertools
# OP syntax :
# add disk -pool <name> { -diskid <diskid> | -diskid auto [-fx | -tdr] } [-fx] [-status { enable | disable } ]
command = (
# one mandatory diskid
("-diskid <diskid>", "-diskid auto", "-diskid auto -fx", "-diskid auto -tdr"),
# one optional fx
(None, "-fx"),
# one optional status
(None, "-status enable", "-status disable")
)
prefix = "add disk -pool <name> "
all_usages = tuple(itertools.product(*command))
print("\n".join(str(prefix + tuple(filter(lambda arg: arg is not None, usage))) for usage in all_usages))
print("total:", len(all_usages))
给我
('add', 'disk', '-pool', '<name>', '-diskid <diskid>')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid <diskid>', '-fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto', '-fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -fx', '-fx', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-status disable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-fx')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-fx', '-status enable')
('add', 'disk', '-pool', '<name>', '-diskid auto -tdr', '-fx', '-status disable')
total: 24
下面的解决方案采用了更通用的方法。首先,parse_commands
将字符串命令转换为列表和字典的嵌套对象,然后 command_combos
从 parse_commands
:
import re, collections itertools
s = 'add disk -pool <name> { -diskid <diskid> | -diskid auto [-fx | -tdr] } [-fx] [-status { enable | disable } ]'
symbols = {'|':None, '{':'}', '[':']'}
def parse_command(s, f = False, t = None):
#take in a string command and parse it
b = []
while s:
n = s.popleft()
if f:
if t is None and n in [*symbols, *symbols.values()]:
s.appendleft(n)
break
if t is not None and n == symbols[t]:
break
if n not in [*symbols, *symbols.values()]:
b.append(n)
elif n == '|':
b = [{'action':'or', 'blocks':(b, list(parse_command(s, f = True, t = None)))}]
else:
b.append({'action':{'{':'mandatory', '[':'optional'}[n], 'blocks':list(parse_command(s, f = True, t = n))})
yield from b
def command_combos(d, c = []):
#recursively traverse parsed command and produce combinations
if not d:
yield c
else:
if isinstance(d[0], str):
yield from command_combos(d[1:], c+[d[0]])
else:
if d[0]['action'] == 'optional':
yield from command_combos(d[1:], c)
for b in (d[0]['blocks'] if d[0]['action'] == 'or' else [d[0]['blocks']]):
for i in command_combos(b, []):
yield from command_combos(d[1:], c+i)
综合起来:
new_s = list(parse_command(collections.deque(re.findall('[\{\[\}\]\|]|\-*\<*\w+\>*', s))))
combos = list(command_combos(new_s))
输出:
[['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-fx', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', '<diskid>', '-tdr', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-fx', '-fx', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-status', 'disable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-fx'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-fx', '-status', 'enable'], ['add', 'disk', '-pool', '<name>', '-diskid', 'auto', '-tdr', '-fx', '-status', 'disable']]