You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Python argparse模块添加可选位置参数组

实现方案

用Python argparse实现和GNU timeout完全一致的参数规则,核心靠3个关键配置:

  • 给解析器设置allow_interspersed_args=False,禁止选项穿插在位置参数之后,强制所有选项必须放在duration前面
  • 命令部分用nargs=argparse.REMAINDER收集duration之后的所有内容,不管是否带短横线,都作为待执行命令和它的参数,避免命令自身的参数被argparse误识别为timeout的选项
  • 自定义参数类型校验函数,对齐原工具的时长、信号格式校验逻辑,非法输入抛出友好错误

完整可运行的参数解析实现代码如下:

import argparse
import re
import signal
import subprocess
import sys

def duration_type(value: str) -> float:
    """校验时长格式,转换为秒数,支持s/m/h/d后缀,默认单位为秒"""
    match = re.fullmatch(r'(\d+\.?\d*)([smhd]?)', value.strip())
    if not match:
        raise argparse.ArgumentTypeError(f"invalid time interval '{value}'")
    num, unit = match.groups()
    num = float(num)
    unit_multiplier = {
        '': 1,
        's': 1,
        'm': 60,
        'h': 3600,
        'd': 86400
    }[unit]
    return num * unit_multiplier

def signal_type(value: str) -> int:
    """校验信号参数,支持信号名(如HUP)或数字格式"""
    try:
        return int(value)
    except ValueError:
        sig_name = value.upper()
        if not sig_name.startswith('SIG'):
            sig_name = f'SIG{sig_name}'
        try:
            return getattr(signal, sig_name)
        except AttributeError:
            raise argparse.ArgumentTypeError(f"invalid signal '{value}'")

def main():
    parser = argparse.ArgumentParser(
        description='Start COMMAND, and kill it if still running after DURATION.',
        usage='timeout [OPTION] DURATION COMMAND [ARG]...\n  or:  timeout [OPTION]',
        add_help=True,
        allow_interspersed_args=False
    )
    # 版本参数
    parser.add_argument('--version', action='version', version='timeout 1.0 (Python implementation)')
    # 布尔开关选项
    parser.add_argument('--preserve-status', action='store_true',
                        help='exit with the same status as COMMAND, even when the command times out')
    parser.add_argument('--foreground', action='store_true',
                        help='when not running timeout directly from a shell prompt, allow COMMAND to read from the TTY and get TTY signals; in this mode, children of COMMAND will not be timed out')
    parser.add_argument('-v', '--verbose', action='store_true',
                        help='diagnose to stderr any signal sent upon timeout')
    # 带参数选项
    parser.add_argument('-k', '--kill-after', type=duration_type, metavar='DURATION',
                        help='also send a KILL signal if COMMAND is still running this long after the initial signal was sent')
    parser.add_argument('-s', '--signal', type=signal_type, default=signal.SIGTERM, metavar='SIGNAL',
                        help="specify the signal to be sent on timeout; SIGNAL may be a name like 'HUP' or a number; see 'kill -l' for a list of signals")
    # 位置参数
    parser.add_argument('duration', type=duration_type, help='timeout duration')
    parser.add_argument('command', nargs=argparse.REMAINDER, help='command to run and its arguments')

    args = parser.parse_args()

    # 校验命令参数非空
    if not args.command:
        parser.error('the following arguments are required: COMMAND')

    # 以下为timeout核心运行逻辑示例,可按需扩展
    # proc = subprocess.Popen(args.command)
    # try:
    #     proc.wait(timeout=args.duration)
    # except subprocess.TimeoutExpired:
    #     if args.verbose:
    #         print(f"timeout: sending signal {args.signal} to command {args.command[0]}", file=sys.stderr)
    #     proc.send_signal(args.signal)
    #     try:
    #         proc.wait(timeout=args.kill_after)
    #     except subprocess.TimeoutExpired:
    #         if args.verbose:
    #             print(f"timeout: sending signal KILL to command {args.command[0]}", file=sys.stderr)
    #         proc.kill()
    # sys.exit(proc.returncode if args.preserve_status else 124)

if __name__ == '__main__':
    main()

行为验证

  • 正常带选项调用:执行python timeout.py -v -k 2s 10s ping baidu.com -c 3,可以正确解析verbose开关、kill-after=2秒、duration=10秒,command为['ping', 'baidu.com', '-c', '3'],-c 3不会被误识别为timeout自身的参数。
  • 选项放在duration之后:执行python timeout.py 5s -v ls,会把-v和ls都归为command内容,和原GNU timeout行为一致,执行时会因找不到-v命令报错。
  • 缺少command参数:执行python timeout.py 5s,会直接报错提示缺少COMMAND参数。
  • 非法参数输入:执行python timeout.py abc ls,会提示invalid time interval 'abc',和原工具报错逻辑对齐。

内容的提问来源于stack exchange,提问作者David SB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.01 04:21:40