如何用Python argparse实现带末尾可选多值参数的子命令
用argparse实现带末尾可选位置参数的子命令
需求:实现命令格式 script.py {scan,list} ... [targets [targets...]],要求两个子命令scan和list都拥有可选的、位于末尾的位置参数(设置nargs=*)。
已尝试的方法及问题
方法1:使用父解析器共享targets参数
- 问题:
- 主脚本帮助信息(
script.py -h)不显示targets参数,仅显示[-h] {scan,list} ...,而非预期的[-h] {scan,list} ... [targets [targets...]] proxy参数会被置于targets之后,无法保证targets始终在末尾
- 主脚本帮助信息(
- 代码:
parser = argparse.ArgumentParser() parent_parser = argparse.ArgumentParser(add_help=False) parent_parser.add_argument('targets', type=str, nargs='*', default="ALL") subparsers = parser.add_subparsers() parser_scan = subparsers.add_parser('scan', parents=[parent_parser]) parser_scan.add_argument('proxy', type=str) parser_list = subparsers.add_parser('list', parents=[parent_parser])
方法2:手动为每个子解析器添加targets参数
- 问题:
- 主脚本帮助信息仍不显示
targets参数 - 若为主解析器添加
targets参数(取消注释第3行),会覆盖子解析器的同名参数,导致args.targets始终返回默认值"ALL"
- 主脚本帮助信息仍不显示
- 代码:
parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() # parser.add_argument('targets', type=str, nargs='*', default="ALL") parser_scan = subparsers.add_parser('scan') parser_scan.add_argument('proxy', type=str) parser_scan.add_argument('targets', type=str, nargs='*', default="ALL") parser_list = subparsers.add_parser('list') parser_list.add_argument('targets', type=str, nargs='*', default="ALL")
方法3:仅在主解析器添加targets参数
- 问题:
- 主脚本帮助信息显示正确,但运行
script.py list Target1时报错:usage: target-utils.py [-h] {scan,list} ... [targets [targets ...]] target-utils.py: error: unrecognized arguments: Target1
- 主脚本帮助信息显示正确,但运行
- 代码:
parser = argparse.ArgumentParser() subparsers = parser.add_subparsers() parser.add_argument('targets', type=str, nargs='*', default="ALL") parser_scan = subparsers.add_parser('scan') parser_scan.add_argument('proxy', type=str) parser_list = subparsers.add_parser('list')
解决方案
核心思路:
- 子解析器中先添加专属参数,再添加targets参数,确保targets在末尾
- 手动自定义主解析器的
usage,让帮助信息显示targets参数 - 为子解析器设置
dest,确保能正确区分子命令
完整代码:
import argparse def main(): # 自定义主解析器的usage,明确显示targets参数 parser = argparse.ArgumentParser( usage="%(prog)s {scan,list} ... [targets [targets...]]" ) subparsers = parser.add_subparsers(dest="command", required=True) # 定义scan子命令:先加proxy参数,再加targets(末尾) parser_scan = subparsers.add_parser('scan') parser_scan.add_argument('proxy', type=str, help="Proxy server address") parser_scan.add_argument( 'targets', type=str, nargs='*', default="ALL", help="Optional target list (default: ALL)" ) # 定义list子命令:直接加targets参数 parser_list = subparsers.add_parser('list') parser_list.add_argument( 'targets', type=str, nargs='*', default="ALL", help="Optional target list (default: ALL)" ) args = parser.parse_args() print(f"Command: {args.command}") print(f"Targets: {args.targets}") if args.command == "scan": print(f"Proxy: {args.proxy}") if __name__ == "__main__": main()
验证效果
- 主帮助信息(
script.py -h)显示正确:usage: script.py {scan,list} ... [targets [targets...]] positional arguments: {scan,list} optional arguments: -h, --help show this help message and exit - scan子命令帮助(
script.py scan -h):usage: script.py scan [-h] proxy [targets ...] positional arguments: proxy Proxy server address targets Optional target list (default: ALL) optional arguments: -h, --help show this help message and exit - 运行测试:
script.py list Target1 Target2:输出Targets: ['Target1', 'Target2']script.py scan http://proxy.com TargetA:输出Proxy: http://proxy.com和Targets: ['TargetA']script.py list:输出Targets: ALL
内容的提问来源于stack exchange,提问作者Keanu
相关产品推荐
相关产品推荐

