首页 > Python > Python 3 标准库实例教程 > 应用程序组成元素

15.3. getopt — 解析命令行参数

目的:命令行选项语法解析

 getopt 模块是原始的命令行选项语法解析器,它支持所有由Unix函数 getopt 建立的惯例。它能解析一串参数序列,例如 sys.argv 并返回包含(选项,参数)对的元组和非选项参数的序列。

可支持的选项语法包括长和短两种形式的选项:

-a
-bval
-b val
--noarg
--witharg=val
--witharg val

注释

getopt 并没有被弃用,但是 argparse 的维护更加活跃,应当被用于新的开发项目上。

函数参数

 getopt() 函数有以下三个参数:

  • 第一个参数是被解析的序列。它通常来自于 sys.argv[1:] (忽略了位于 sys.arg[0] 位置上的程序名)。
  • 第二个参数是对单字符选项的定义字符串。如果其中一个选项需要参数,其代表字符后会有一个冒号。
  • 第三个参数,如果用到的话,则是长类型选项名序列。长类型选项往往多于一个字符表示,如 --noarg 或 --witharg 。在该序列内的选项名应当不包括 -- 前缀。如果长选项需要后跟参数,选项名后将有一个 = 后缀。

长和短形式的选项将在单次调用后被合并。

短选项

此示例程序接受三个选项。-a 是一个普通的标识符,而 -b-c 需要一个参数。选项定义字符串为 "ab:c:"

  • 在选项定义字符串中,不需要前导符号 -
  • 需要参数的选项,在选项定义字符串后需要添加后缀 :

getopt_short.py

import getopt

opts, args = getopt.getopt(['-a', '-bval', '-c', 'val'], 'ab:c:')

for opt in opts:
    print(opt)

此程序传递一个模拟的选项值列表给 getopt() 函数来展示它是如何处理的。以下为结果:

  • 上例中的 opts 变量接受了一个返回的列表;
  • opts 中的每一个元素都是 (选项, 参数) 形式的元组。
  • args 参数本应接受一个由处理后剩余的参数组成的列表,本例中则为一个空列表。
$ python3 getopt_short.py

('-a', '')
('-b', 'val')
('-c', 'val')

长选项格式

对于具有两个选项 --noarg--witharg 的程序,长选项定义语句应该为 [ 'noarg', 'witharg=' ]

  • 无参数选项定义字符串不需带有前导符号 --
  • 需要参数的长选项,在定义时需要跟后缀等号 =

getopt_long.py

import getopt

opts, args = getopt.getopt(
    ['--noarg',             # 无参数选项
     '--witharg', 'val',    # 带参数选项
     '--witharg2=another'], # 也可用等号连接选项与参数
    '',
    ['noarg', 'witharg=', 'witharg2='],
)
for opt in opts:
    print(opt)

因为此示例中没有使用短格式的选项,因此 getopt() 函数的第二个返回值 args 为空。

$ python3 getopt_long.py

('--noarg', '')
('--witharg', 'val')
('--witharg2', 'another')

一个完整的例子

此示例是一个更加完整的程序,它带有五个选项:-o-v--output--verbose--version

-o--output,和 --version都需要一个参数。

getopt_example.py

import getopt
import sys

version = '1.0'
verbose = False
output_filename = 'default.out'

print('ARGV      :', sys.argv[1:])

try:
    options, remainder = getopt.getopt(
# 这里将解析后的选项-参数对存入变量 options 了,勿与后文的 opt,arg 混淆
        sys.argv[1:],
        'o:v',
        ['output=',
         'verbose',
         'version=',
         ])
except getopt.GetoptError as err:
    print('ERROR:', err)
    sys.exit(1)

print('OPTIONS   :', options)

for opt, arg in options: 
# arg 是此选项对应的参数, 不要与上文的 remainder 混淆
    if opt in ('-o', '--output'):
        output_filename = arg
    elif opt in ('-v', '--verbose'):
        verbose = True
    elif opt == '--version':
        version = arg

print('VERSION   :', version)
print('VERBOSE   :', verbose)
print('OUTPUT    :', output_filename)
print('REMAINING :', remainder)

此程序可以通过多种方式被调用。当不带参数地调用它时, 将会使用默认的设置。

$ python3 getopt_example.py

ARGV      : []
OPTIONS   : []
VERSION   : 1.0
VERBOSE   : False
OUTPUT    : default.out
REMAINING : []

一个单字符选项与它的参数可以用空格分隔。

$ python3 getopt_example.py -o foo

ARGV      : ['-o', 'foo']      # 用空格分隔的 选项 参数
OPTIONS   : [('-o', 'foo')]
VERSION   : 1.0
VERBOSE   : False
OUTPUT    : foo
REMAINING : []

或者, 可以直接将单字符选项与其参数组合。

$ python3 getopt_example.py -ofoo

ARGV      : ['-ofoo']   # 直接连写的 选项参数
OPTIONS   : [('-o', 'foo')] # 依然成功解析
VERSION   : 1.0
VERBOSE   : False
OUTPUT    : foo
REMAINING : []

一个长格式的选项也可以用空格分隔其参数。

$ python3 getopt_example.py --output foo

ARGV      : ['--output', 'foo']
OPTIONS   : [('--output', 'foo')]
VERSION   : 1.0
VERBOSE   : False
OUTPUT    : foo
REMAINING : []

但当要组合一个长格式选项与其参数时,应当使用等号 = 分隔。

$ python3 getopt_example.py --output=foo

ARGV      : ['--output=foo']
OPTIONS   : [('--output', 'foo')]
VERSION   : 1.0
VERBOSE   : False
OUTPUT    : foo
REMAINING : []

缩写长格式选项

只要提供了唯一的前缀,长格式选项不必在命令行上完整地拼出。

$ python3 getopt_example.py --o foo # 这里可不是 -o 哦

ARGV      : ['--o', 'foo']
OPTIONS   : [('--output', 'foo')]
VERSION   : 1.0
VERBOSE   : False
OUTPUT    : foo
REMAINING : []

如果提供地前缀并不唯一,则会抛出异常。

$ python3 getopt_example.py --ver 2.0
# --version 与 --verbose 混淆

ARGV      : ['--ver', '2.0']
ERROR: option --ver not a unique prefix

GNU 风格的选项解析

通常地,一旦遇到第一个非选项参数,选项处理就会停止。

$ python3 getopt_example.py -v not_an_option --output foo

ARGV      : ['-v', 'not_an_option', '--output', 'foo']
OPTIONS   : [('-v', '')]
VERSION   : 1.0
VERBOSE   : True
OUTPUT    : default.out
REMAINING : ['not_an_option', '--output', 'foo']

为了在命令行以任意顺序混合选项与非选项,使用 gnu_getopt() 来代替 getopt()

getopt_gnu.py

import getopt
import sys

version = '1.0'
verbose = False
output_filename = 'default.out'

print('ARGV      :', sys.argv[1:])

try:
    options, remainder = getopt.gnu_getopt(
        sys.argv[1:],
        'o:v',
        ['output=',
         'verbose',
         'version=',
         ])
except getopt.GetoptError as err:
    print('ERROR:', err)
    sys.exit(1)

print('OPTIONS   :', options)

for opt, arg in options:
    if opt in ('-o', '--output'):
        output_filename = arg
    elif opt in ('-v', '--verbose'):
        verbose = True
    elif opt == '--version':
        version = arg

print('VERSION   :', version)
print('VERBOSE   :', verbose)
print('OUTPUT    :', output_filename)
print('REMAINING :', remainder)

在上一个示例中更改了函数调用后,两者的差异变得清楚了。

$ python3 getopt_gnu.py -v not_an_option --output foo

ARGV      : ['-v', 'not_an_option', '--output', 'foo']
OPTIONS   : [('-v', ''), ('--output', 'foo')]
VERSION   : 1.0
VERBOSE   : True
OUTPUT    : foo
REMAINING : ['not_an_option']

结束参数处理

如果 getopt() 在输入的参数中遇到 "--",它将停止将剩余的参数作为选项处理。此特性可用来传递格式上类似于选项的参数,例如以 - 符号开头的文件名。

$ python3 getopt_example.py -v -- --output foo

ARGV      : ['-v', '--', '--output', 'foo']
OPTIONS   : [('-v', '')]  # -- 本身不作为参数传递
VERSION   : 1.0
VERBOSE   : True
OUTPUT    : default.out
REMAINING : ['--output', 'foo']
# 之后的参数都将存入 getopt() 的第二个返回值

参阅