实现“[command] [action] [parameter]”风格的命令行界面?

Posted

技术标签:

【中文标题】实现“[command] [action] [parameter]”风格的命令行界面?【英文标题】:Implementing a "[command] [action] [parameter]" style command-line interfaces? 【发布时间】:2010-09-26 14:53:00 【问题描述】:

什么是实现命令行 UI 的“最干净”的方式,类似于 git 的,例如:

git push origin/master
git remote add origin git://example.com master

理想情况下还允许更灵活的解析,例如,

jump_to_folder app theappname v2
jump_to_folder app theappname source
jump_to_folder app theappname source v2
jump_to_folder app theappname build v1
jump_to_folder app theappname build 1
jump_to_folder app theappname v2 build

jump_to_folder 是脚本名称,app 是命令,theappname 是“固定位置”参数,“build”和“v2”等是参数(例如,可能的参数可以是任何数字/任何以 av 为前缀的数字,或 build/source/tmp/config)

我可以手动解析带有一系列if/else/elifs 的参数,但是必须有更优雅的方法来做到这一点?

作为一个完全理论上的例子,我可以描述 UI 架构..

app:
    fixed: application_name

    optional params:
        arg subsection:
            "build"
            "source"
            "tmp"
            "config"

        arg version:
            integer
            "v" + integer

然后通过上述模式解析提供的参数,并得到一个字典:

>>> print schema.parse(["app", "theappname", "v1", "source"])

    "application_name": "theappname",
    "params":
        "subsection": "source",
        "version":"v1"
    

这样的系统存在吗?如果没有,我将如何按照这些思路实施?

【问题讨论】:

【参考方案1】:

argparse 非常适合,特别是 "sub-commands" 和位置参数

import argparse


def main():
    arger = argparse.ArgumentParser()

    # Arguments for top-level, e.g "subcmds.py -v"
    arger.add_argument("-v", "--verbose", action="count", default=0)

    subparsers = arger.add_subparsers(dest="command")

    # Make parser for "subcmds.py info ..."
    info_parser = subparsers.add_parser("info")
    info_parser.add_argument("-m", "--moo", dest="moo")

    # Make parser for "subcmds.py create ..."
    create_parser = subparsers.add_parser("create")
    create_parser.add_argument("name")
    create_parser.add_argument("additional", nargs="*")

    # Parse
    opts = arger.parse_args()

    # Print option object for debug
    print opts

    if opts.command == "info":
        print "Info command"
        print "--moo was %s" % opts.moo

    elif opts.command == "create":
        print "Creating %s" % opts.name
        print "Additional: %s" % opts.additional

    else:
        # argparse will error on unexpected commands, but
        # in case we mistype one of the elif statements...
        raise ValueError("Unhandled command %s" % opts.command)


if __name__ == '__main__':
    main()

可以这样使用:

$ python subcmds.py create myapp v1 blah
Namespace(additional=['v1', 'blah'], command='create', name='myapp', verbose=0)
Creating myapp
Additional: ['v1', 'blah']
$ python subcmds.py info --moo
usage: subcmds.py info [-h] [-m MOO]
subcmds.py info: error: argument -m/--moo: expected one argument
$ python subcmds.py info --moo 1
Namespace(command='info', moo='1', verbose=0)
Info command
--moo was 1

【讨论】:

不错!这正是医生吩咐的!谢谢!【参考方案2】:

cmd 模块可能适用于此。

例子:

import cmd

class Calc(cmd.Cmd):
    def do_add(self, arg):
        print sum(map(int, arg.split()))

if __name__ == '__main__':
    Calc().cmdloop()

运行它:

$python calc.py
(Cmd) add 4 5
9
(Cmd) help

Undocumented commands:
======================
add  help

(Cmd)

请参阅Python docs 或PyMOTW site 了解更多信息。

【讨论】:

【参考方案3】:

直接来自我的一个脚本:

import sys

def prog1_func1_act1(): print "pfa1"
def prog2_func2_act2(): print "pfa2"

commands = 
    "prog1 func1 act1": prog1_func1_act1,
    "prog2 func2 act2": prog2_func2_act2


try:
    commands[" ".join(sys.argv[1:])]()
except KeyError:
    print "Usage: ", commands.keys()

这是一个非常快速和肮脏的解决方案,但非常适合我的使用。如果我稍微清理一下,我可能会添加argparse 来解析位置和关键字参数。

【讨论】:

这个问题是参数是固定的。例如,你不能轻易拥有一个“v001”..“v102”选项,没有为每个组合创建一个键.. 是的,我知道,这就是我提到 argparse 的原因。例如,如果您的“命令”和“操作”相对较少,但参数很多,您可以使用我使用的方法分派到特定操作,然后将参数(和可选的关键字参数)传递给使用 argparse 的脚本. 另外,您可以添加一个元命令“帮助”,打印出命令的内容并显示它们的 .__doc__ 字符串 此外,args 并不是真正固定的,因为命令列表中的命令会获取所有 args,因此可以在每个命令中解析它们(并且可以排除常见的解析)。或者,如果您的意思是命令列表是有限的,请考虑在命令对象中覆盖 getkey【参考方案4】:

Python 有一个用于解析命令行选项的模块,optparse。

【讨论】:

不幸的是,它解析命令行 options,而不是 dbr 要求的 arguments 没错。据我所知,它最适合“-f 2 -v -z 55”类型的参数,除非我遗漏了什么?【参考方案5】:

您可能想看看cliff – Command Line Interface Formulation Framework

【讨论】:

【参考方案6】:

这是我的建议。

    稍微改变你的语法。

    使用 optparse。

理想情况下还允许更灵活的解析,例如,

jump_to_folder -n theappname -v2 cmd 
jump_to_folder -n theappname cmd source 
jump_to_folder -n theappname -v2 cmd source 
jump_to_folder -n theappname -v1 cmd build 
jump_to_folder -n theappname -1 cmd build 
jump_to_folder -n theappname -v2 cmd build

那么你有 1 或 2 个参数:命令总是第一个参数。它的可选参数始终是第二个参数。

其他都是选项,没有特定的顺序。

【讨论】:

以上是关于实现“[command] [action] [parameter]”风格的命令行界面?的主要内容,如果未能解决你的问题,请参考以下文章

多线程的实现之实现Runnable接口

当一个类实现一个接口时,它必须实现该接口中的所有方法。(判断题)

项目——博客系统

java中,一个类实现了某个接口,啥意思?实现它,可以干啥

JAVA框架如何实现调用接口的实现类的呢?例实现httpsessionlistener接口类被调。

水平集图像分割并行加速算法设计与实现(串行OpenMPCUDA)——串行实现篇