使用 argparse 构建 Python 命令行工具

目前在公司需要构建一套环境部署工具,在测试阶段该工具只提供 CLI 接口进行测试,需要通过不同参数的支持实现不同功能和参数设定。作为一个脚本自然选择 Python 作为开发语言,为了实现工具的小巧,使用内置的argparse来实现参数的解析。本文章主要介绍该库的使用方法。

argparse 作为 Python 内置库,有详细的官方文档官方教程

argparse 的使用方法非常简单,共三步:

  1. 创建 ArgumentParser()对象;
  2. 调用 add_argument()方法添加参数;
  3. 使用 parse_args()解析添加的参数。

用 argparse 实现多样的命令行工具,关键就在添加参数这个函数,其参数可选项非常多。

argpaser 的功能

argparse — Parser for command-line options, arguments and sub-commands

这是 argparse 官方文档的标题,通过标题可以看到,argparse 可以解析命令行的option/arguments/sub-commands

官方的文档和网上的资料很详细,本节不会介绍具体的参数和细节用法。本节会介绍参数的三种类型,以便各位在开发自己工具的时候可以做到有的放矢。

占位参数

占位参数即 argument,顾名思义即这个参数是必须选的。

以 Linux 创建本地用户的命令useradd为例子:

1
2
$ useradd -h
usage: useradd [option] LOGIN

其中,LOGIN就是一个占位参数。现在我们用 argparser 写一个高仿的useradd程序,直接看代码。

1
2
3
4
5
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("LOGIN")
args = parser.parse_args()
print args.LOGIN

该代码的运行结果如下:

1
2
3
4
5
6
7
8
$ python useradd.py -h
usage: useradd.py [-h] LOGIN

positional arguments:
LOGIN

optional arguments:
-h, --help show this help message and exit

OK,我们已经写出来useradd程序类似的 help 信息了,那么怎么获取传入参数的值呢?

add_argument会把参数名注册为解析器实例的成员变量,注意代码第5行。使用效果如下:

1
2
$ python useradd.py gulei
gulei

可选参数

继续useradd的例子,该程序有很多option,比如指定用户的用户组-g、用户的 id-u等等,如果不指定则使用默认值。这种模式的参数就是可选参数。除此之外,我们可以发现大部分命令行工具的可选参数都是以-或者--开头的,argparser 也是如此,我们再次以useradd程序为例,增加-u参数允许用户指定用户 ID。

1
2
3
4
5
6
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("LOGIN")
parser.add_argument('-u', default=1000)
args = parser.parse_args()
print "%s's uid is %s" % (args.LOGIN, args.u)

代码运行结果如下:

1
2
3
4
5
6
7
8
9
$ python useradd.py -h
usage: useradd.py [-h] [-u U] LOGIN

positional arguments:
LOGIN

optional arguments:
-h, --help show this help message and exit
-u U

代码传入参数运行结果:

1
2
3
4
5
6
$ python useradd.py gulei
gulei's uid is 1000
$ python useradd.py -u 1024 gulei
gulei's uid is 1024
$ python useradd.py -u=2048 gulei
gulei's uid is 2048

子命令

对于useradd程序子命令是更高级的用法了,目前该程序是使用不到的。但是没有需求我们就创造需求。

假设我们要让useradd程序能设置用户的年龄,提供出类似useradd set_age <username> <age>的命令行工具。

构建一层子命令就是对解析器增加一套subparsers,具体看代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import argparse

parser = argparse.ArgumentParser()
# 构建子解析器集合,子解析器命名为 command
subparsers = parser.add_subparsers(help='USERADD SUBCOMMAND', dest='command')
# 构建年龄解析器
age_parser = subparsers.add_parser('set_age', help="Set user's age")
# 构建性别解析器
gender_parser = subparsers.add_parser('set_gender', help="Set user's gender")
age_parser.add_argument('name')
age_parser.add_argument('age', type=int)
gender_parser.add_argument('name')
gender_parser.add_argument('gender', type=str)
args = parser.parse_args()

if args.command == 'set_age':
print "%s's age is %d" % (args.name, args.age)
elif args.command == 'set_gender':
print "%s is a %s" % (args.name, args.gender)
else:
pass

可以看到命令帮助选择如下:

1
2
3
4
5
6
7
8
9
10
$ python useradd.py -h
usage: useradd.py [-h] {set_age,set_gender} ...

positional arguments:
{set_age,set_gender} USERADD SUBCOMMAND
set_age Set user's age
set_gender Set user's gender

optional arguments:
-h, --help show this help message and exit

命令执行结果如下:

1
2
3
4
$ python useradd.py set_age gulei 26
gulei's age is 26
$ python useradd.py set_gender gulei man
gulei is a man

总结

更多的实现细节我们可以去 Google 和阅读文档,但是在清楚了使用模式之后,我们可以随心所欲得设计程序。

三种模式可以叠加使用,实现更复杂的 CLI 工具。