Python 使用getopt解析命令行参数

Python中getopt是一个命令行参数解析的模块,用于处理命令行选项和参数。它能够将命令行参数解析为一个选项列表和一个参数列表,并对选项进行验证和转换。一般在运行Python脚本时需要解析传递的命令行参数时使用。本文主要介绍 Python 使用getopt解析命令行参数方法,以及相关的示例代码。

1、getopt 模块

此模块可协助脚本解析 sys.argv 中的命令行参数。 它支持与 Unix getopt() 函数相同的惯例(包括形式如 '-' 与 '--' 的参数的特殊含义)。 也能通过可选的第三个参数来使用与 GNU 软件所支持形式相类似的长选项。

1)getopt.getopt(args, shortopts, longopts=[])

方法作用是用于解析命令行选项与形参列表, args 为要解析的参数列表,不包含最开头的对正在运行的程序的引用。 通常这意味着 sys.argv[1:]。 shortopts 为脚本所要识别的字母选项,包含要求后缀一个冒号 (':';即与 Unix getopt() 所用的格式相同) 的选项。另外,与 GNU getopt() 不同,在非选项参数之后,所有后续参数都会被视为非选项。 这类似于非 GNU Unix 系统的运作方式。

import getopt
import sys

# 命令行参数列表
argv = sys.argv[1:]

# 定义短选项字符串
short_options = "ho:v"

# 定义长选项字符串
long_options = ["help", "output=", "verbose"]

# 使用 getopt 解析命令行参数
try:
    opts, args = getopt.getopt(argv, short_options, long_options)
except getopt.GetoptError:
    print("Usage: example.py -o <outputfile> -v")
    sys.exit(2)

output_file = None
verbose = False

# 处理解析结果
for opt, arg in opts:
    if opt in ("-h", "--help"):
        print("Usage: example.py -o <outputfile> -v")
        sys.exit()
    elif opt in ("-o", "--output"):
        output_file = arg
    elif opt in ("-v", "--verbose"):
        verbose = True

print("Output file:", output_file)
print("Verbose mode:", verbose)
print("Remaining args:", args)

注意:getopt 模块是一个命令行选项解析器,其 API 设计会让 C getopt() 函数的用户感到熟悉。 不熟悉 C getopt() 函数或者希望写更少代码并获得更完善帮助和错误消息的用户应当考虑改用 argparse 模块。

2)getopt.gnu_getopt(args, shortopts, longopts=[])

此函数与 getopt() 类似,区别在于它默认使用 GNU 风格的扫描模式。 意味着选项和非选项参数可能会混在一起。 getopt() 函数将在遇到非选项参数时立即停止处理选项。

如果选项字符串的第一个字符为 '+',或者如果设置了环境变量 POSIXLY_CORRECT,则选项处理会在遇到非选项参数时立即停止。

import getopt
import sys

# 命令行参数列表
args = ["--input", "inputfile.txt", "--output", "outputfile.txt", "--verbose", "--help"]

# 定义短选项字符串
shortopts = "hi:o:v"

# 定义长选项列表
longopts = ["help", "input=", "output=", "verbose"]

# 使用 getopt.gnu_getopt 解析命令行参数
opts, args = getopt.gnu_getopt(args, shortopts, longopts)

input_file = None
output_file = None
verbose = False

# 处理解析结果
for opt, arg in opts:
    if opt in ("-h", "--help"):
        print("Usage: example.py -i <inputfile> -o <outputfile> -v")
        sys.exit()
    elif opt in ("-i", "--input"):
        input_file = arg
    elif opt in ("-o", "--output"):
        output_file = arg
    elif opt in ("-v", "--verbose"):
        verbose = True

print("Input file:", input_file)
print("Output file:", output_file)

3)exception getopt.GetoptError

当参数列表中出现不可识别的选项或者当一个需要参数的选项未带参数时将引发此异常。 此异常的参数是一个指明错误原因的字符串。 对于长选项,将一个参数传给不需要参数的选项也将导致引发此异常。 msg 和 opt 属性会给出错误消息和关联的选项;如果没有关联到异常的特定选项,则 opt 将为空字符串。

exception getopt.error GetoptError的别名;用于向后兼容。

参考文档:https://docs.python.org/zh-cn/3/library/getopt.html

2、 argparse 模块

可以使用更少的代码并附带更详细的帮助与错误消息生成等价的命令行接口,如下,

import argparse

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('-o', '--output')
    parser.add_argument('-v', dest='verbose', action='store_true')
    args = parser.parse_args()
    print(args)

参考文档https://docs.python.org/zh-cn/3/library/argparse.html#module-argparse

3、getopt 模块使用示例

getopt 模块使用完整示例,包括exception getopt.GetoptError的处理,日志的输出,参数获取判断,如下,

import getopt
import os
import platform
import sys


TERM = os.getenv('TERM', '')
IS_ANSI_TERMINAL = TERM in (
    'eterm-color',
    'linux',
    'screen',
    'vt100',
) or TERM.startswith('xterm')

RESET = 0
BOLD = 1
UNDERLINE = 4
NEGATIVE = 7
NO_BOLD = 21
NO_UNDERLINE = 24
POSITIVE = 27
BLACK = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
LIGHT_GRAY = 37
DEFAULT = 39
BLACK_BACKGROUND = 40
RED_BACKGROUND = 41
GREEN_BACKGROUND = 42
YELLOW_BACKGROUND = 43
BLUE_BACKGROUND = 44
MAGENTA_BACKGROUND = 45
CYAN_BACKGROUND = 46
LIGHT_GRAY_BACKGROUND = 47
DEFAULT_BACKGROUND = 49
DARK_GRAY = 90                 # xterm
LIGHT_RED = 91                 # xterm
LIGHT_GREEN = 92               # xterm
LIGHT_YELLOW = 93              # xterm
LIGHT_BLUE = 94                # xterm
LIGHT_MAGENTA = 95             # xterm
LIGHT_CYAN = 96                # xterm
WHITE = 97                     # xterm
DARK_GRAY_BACKGROUND = 100     # xterm
LIGHT_RED_BACKGROUND = 101     # xterm
LIGHT_GREEN_BACKGROUND = 102   # xterm
LIGHT_YELLOW_BACKGROUND = 103  # xterm
LIGHT_BLUE_BACKGROUND = 104    # xterm
LIGHT_MAGENTA_BACKGROUND = 105 # xterm
LIGHT_CYAN_BACKGROUND = 106    # xterm
WHITE_BACKGROUND = 107         # xterm

def sprint(text, *colors):
    """Format text with color or other effects into ANSI escaped string."""
    return "\33[{}m{content}\33[{}m".format(";".join([str(color) for color in colors]), RESET, content=text) if IS_ANSI_TERMINAL and colors else text

def println(text, *colors):
    """Print text to standard output."""
    sys.stdout.write(sprint(text, *colors) + "\n")

def print_err(text, *colors):
    """Print text to standard error."""
    sys.stderr.write(sprint(text, *colors) + "\n")

def wtf(message, exit_code=1):
    """What a Terrible Failure!"""
    print_log(message, RED, BOLD)
    if exit_code is not None:
        sys.exit(exit_code)

def print_log(text, *colors):
    """Print a log message to standard error."""
    sys.stderr.write(sprint("{}: {}".format(script_name, text), *colors) + "\n")
script_name="cjavapy"
_options = [
    'help',
    'version',
    'gui',
    'force',
    'playlists',
]
_short_options = 'hVgfl'

_help = """Usage: {} [OPTION]... [URL]...
TODO
""".format(script_name)


def main(**kwargs):
    """Main entry point.
    dev
    """

    # Get (branch, commit) if running from a git repo.
    head = 'repo_path'

    # Get options and arguments.
    try:
        opts, args = getopt.getopt(sys.argv[1:], _short_options, _options)
    except getopt.GetoptError as e:
        wtf("""
    [Fatal] {}.
    Try '{} --help' for more options.""".format(e, script_name))

    if not opts and not args:
        # Display help.
        print(_help)
        # Enter GUI mode.
        #from .gui import gui_main
        #gui_main()
    else:
        conf = {}
        for opt, arg in opts:
            if opt in ('-h', '--help'):
                # Display help.
                print(_help)

            elif opt in ('-V', '--version'):
                # Display version.
                println("cjavapy:", BOLD)
                println("    version:  {}".format(__version__))
                if head is not None:
                    println("    branch:   {}\n    commit:   {}".format(*head))
                else:
                    println("    branch:   {}\n    commit:   {}".format("(stable)", "(tag v{})".format(__version__)))

                println("    platform: {}".format(platform.platform()))
                println("    python:   {}".format(sys.version.split('\n')[0]))

            elif opt in ('-g', '--gui'):
                # Run using GUI.
                conf['gui'] = True

            elif opt in ('-f', '--force'):
                # Force download.
                conf['force'] = True

            elif opt in ('-l', '--playlist', '--playlists'):
                conf['playlist'] = True

        if args:
            if 'gui' in conf and conf['gui']:
                # Enter GUI mode.
                from .gui import gui_main
                gui_main(*args, **conf)
            else:
                # Enter console mode.
                from .console import console_main
                console_main(*args, **conf)
if __name__ == '__main__':
    main()

推荐阅读
cjavapy编程之路首页