命令行帮助信息、手动和交互执行
一、方式一
1、先定义一个命令行解析类
class CommandLineParser: def __init__(self): self.arguments = {} self.valid_options = { "help", "mode", "interval", "export", "wave_data_export", "wave_set", "ip", "serial_path", "rate", "devid", "url", "topic", "user", "passw", } def parse(self, args): current_name = "" values = [] invalid_options = [] for arg in args: if arg.startswith("--"): if current_name != "" and values: self.arguments[current_name] = values values = [] current_name = arg[2:] elif arg.startswith("-"): if current_name != "" and values: self.arguments[current_name] = values values = [] current_name = arg[1:] else: values.append(arg) if current_name != "": self.arguments[current_name] = values for key in self.arguments.keys(): if key not in self.valid_options: invalid_options.append(key) if invalid_options: raise ValueError(f"Invalid option(s): {' '.join(invalid_options)}") def contains(self, name): return name in self.arguments def get_help_message(self): script_name = sys.argv[0] return f""" Usage: python {script_name} [options] Options: --help Show this help message and exit --mode Choose connection mode (1 for MIB RS232, 2 for LAN) --interval Data Transmission interval (1-5) --export Data export option (1-4) --wave_set Waveform data export priority option (0-12) --wave_data_export Choose Waveform data export scale option (1-2) --ip Target IP address for LAN --serial_path Target Serial port path for MIB --rate Serial baudrate for MIB --devid Device ID/Name for export --url Data export URL (JSON or MQTT WebSocket) --topic MQTT Topic --user MQTT Username --passw MQTT Password Examples: python {script_name} --mode 1 --interval 1 --export 1 --wave_set 0 --wave_data_export 1 --serial_path /dev/ttyS5 --rate 115200 python {script_name} --mode 2 --interval 1 --export 1 --wave_set 0 --wave_data_export 1 --ip localhost """
2、定义一个获取交互的函数,命令参数没有就从交互中取
def get_input(parser, key, options=None, prompt="", default=None): if options is None: options = [] if parser.arguments.get(key): return parser.arguments[key][0] else: if default is not None: return default if options: for option in options: print(option) return input(prompt)
3、使用get_input取值
ip_address_remote = get_input(parser, 'ip', prompt="Enter the target IP address of the monitor assigned by DHCP: ", default="localhost")
4、程序入口
def main(args): parser = CommandLineParser() try: parser.parse(args) if parser.contains('help'): print(parser.get_help_message()) return except ValueError as e: print(e) print(parser.get_help_message()) return ser_connect_set = get_input(parser, 'mode', ["1. Connect via MIB RS232 port", "2. Connect via LAN port"], "Choose connection mode (1-2): ", default='2') if ser_connect_set == "1": connect_via_MIB(args) elif ser_connect_set == "2": connect_via_lan(args) else: print("Invalid mode selected!") if __name__ == '__main__': main(sys.argv[1:])
二、方式二(getopt)
1、定义一个解析函数
def print_help(): print("python {} ".format(__file__)) print("python {} --serial-path=/dev/ttyS0 --serial-rate=115200" .format(__file__)) print("python {} --serial-path=COM3 --serial-rate=115200" .format(__file__)) def parse_args(argv): try: options, args = getopt.getopt(argv, "h", ["help", "serial-path=", "serial-rate="]) except getopt.GetoptError: sys.exit() serial_path, serial_rate = "/dev/ttyS0", 115200 for option, value in options: # [('--serial-path', 'COM5')] if option in ("-h", "--help"): print_help() sys.exit() if option in "--serial-path": serial_path = value if option in "--serial-rate": serial_rate = int(value) return serial_path, serial_rate
2、程序入库
if __name__ == '__main__': serial_path, serial_rate = parse_args(sys.argv[1:]) if not check_serial_port(serial_path): sys.exit(-1) simulator = PhilipsMpMPMonitorSimulator(serial_path, serial_rate) signal.signal(signal.SIGINT, signal_handler)
3、关于getopt模块的介绍
导入模块
import getopt import sys
基本语法
getopt.getopt(args, shortopts, longopts=[])
参数说明:
args: 通常是 sys.argv[1:],即命令行参数列表(不包括脚本名)
shortopts: 短选项字符串,每个字符代表一个选项
longopts: 长选项列表
使用示例
import getopt import sys def main(): try: opts, args = getopt.getopt(sys.argv[1:], "ho:vf:dm:", [ "help", "output=", "file=", "debug", "mode=", "name=", "version" ]) except getopt.GetoptError as err: print(str(err)) usage() sys.exit(2) output = None verbose = False input_file = None debug = False mode = "default" name = None for o, a in opts: if o in ("-h", "--help"): usage() sys.exit() elif o in ("-o", "--output"): output = a print(output) elif o == "-v": verbose = True print(verbose) elif o in ("-f", "--file"): input_file = a print(input_file) elif o in ("-d", "--debug"): debug = True print(debug) elif o in ("-m", "--mode"): mode = a print(mode) elif o == "--name": name = a print(name) elif o == "--version": print("Script Version 1.0") sys.exit() else: assert False, "unhandled option" def usage(): print("""Usage: script.py [OPTIONS] Options: -h, --help Show this help message and exit -o OUTPUT, --output=OUTPUT Specify output file -v Verbose mode -f FILE, --file=FILE Input file -d, --debug Enable debug mode -m MODE, --mode=MODE Specify operation mode --name=NAME Specify name --version Show version information """) if __name__ == "__main__": main()
关键点:
短选项格式:单个字母后跟冒号表示该选项需要参数,如 "ho:vf:dm:"
h
: 不需要参数o:
: 需要参数v
: 不需要参数f:
: 需要参数d
: 不需要参数m:
: 需要参数- name这里没有短选项
长选项格式:选项名后跟等号表示需要参数,如 ["help", "output="]
getopt() 返回两个值:(options, args)
options 是一个 (option, value) 对的列表,列表套元组
args 包含那些没有被 opts 处理的命令行参数
错误处理:
使用 try-except 块来捕获 getopt.GetoptError 异常,这样可以处理无效的命令行参数。
三、最推荐使用的argparse和click
1、argparse
:
是Python标准库中最推荐使用的命令行解析模块。它功能强大,使用简单,并能自动生成帮助和使用信息。
import argparse parser = argparse.ArgumentParser(description='Description of your program') parser.add_argument('-o', '--output', help='Output file') parser.add_argument('-v', '--verbose', action='store_true', help='Verbose mode') args = parser.parse_args() if args.verbose: print("Verbose mode enabled")
2、click
:
这是一个第三方库,设计得非常优雅和直观。它使用装饰器来定义命令行接口,非常适合构建复杂的命令行应用。
import click @click.command() @click.option('--count', default=1, help='Number of greetings.') @click.option('--name', prompt='Your name', help='The person to greet.') def hello(count, name): for _ in range(count): click.echo(f"Hello, {name}!") if __name__ == '__main__': hello()