2008-12-12 30 views
11

cách "sạch" để thực hiện một dòng lệnh giao diện người dùng, tương tự như git, ví dụ là gì:Thực hiện một giao diện dòng lệnh kiểu lệnh [[command] [action] [parameter] "?

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

Lý tưởng nhất cũng cho phép phân tích linh hoạt hơn, ví dụ,

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 là tên tập lệnh, app là lệnh, theappname là thông số "vị trí cố định", "xây dựng" và "v2" v.v. là các đối số (Ví dụ: đối số có thể là bất kỳ số nào/số bất kỳ được đặt trước bằng av hoặc build/nguồn/tmp/config)

Tôi chỉ có thể phân tích cú pháp các đối số bằng một loạt các if/else/elifs theo cách thủ công, nhưng phải có cách thanh lịch hơn để thực hiện việc này?

Như một ví dụ hoàn toàn về mặt lý thuyết, tôi có thể mô tả giản đồ UI ..

app: 
    fixed: application_name 

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

     arg version: 
      integer 
      "v" + integer 

Sau đó, phân tích các đối số được cung cấp mặc dù sơ đồ trên, và nhận được một cuốn từ điển:

>>> print schema.parse(["app", "theappname", "v1", "source"]) 
{ 
    "application_name": "theappname", 
    "params":{ 
     "subsection": "source", 
     "version":"v1" 
    } 
} 

Liệu như một hệ thống tồn tại? Nếu không, làm thế nào tôi sẽ đi về việc thực hiện một cái gì đó dọc theo những dòng này?

Trả lời

10

argparse là hoàn hảo cho điều này, đặc biệt "sub-commands" và args vị trí

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() 

Điều này có thể được sử dụng như sau:

$ 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 
+0

Rất tuyệt! Đó là chính xác những gì bác sĩ đã ra lệnh! Cảm ơn! –

+0

ví dụ tốt về cách sử dụng subparsers. Cảm ơn! – jozefow

2

Trực tiếp từ một trong những kịch bản của tôi:

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() 

Đó là một giải pháp khá nhanh chóng và dơ bẩn, nhưng hoạt động tuyệt vời cho sử dụng của tôi. Nếu tôi đã làm sạch nó một chút, tôi có lẽ sẽ thêm argparse vào hỗn hợp để phân tích cú pháp đối số vị trí và từ khóa.

+0

Vấn đề với điều này là các đối số được cố định .. Ví dụ, bạn không thể dễ dàng có tùy chọn "v001" .. "v102", thiếu tạo khóa cho mọi kết hợp .. – dbr

+0

Vâng tôi biết, và đó là lý do tại sao tôi đề cập đến argparse. Ví dụ: nếu bạn có ít "lệnh" và "hành động", nhưng có nhiều tham số, bạn có thể gửi đến hành động cụ thể bằng cách tiếp cận tôi sử dụng, sau đó chuyển tham số (và đối số từ khóa tùy chọn) cho tập lệnh sử dụng argparse . – kmelva

+0

plus, bạn có thể thêm lệnh meta 'help' để in nội dung của lệnh và hiển thị các chuỗi .__ doc__ của chúng – pjz

1

Python có mô-đun để phân tích cú pháp tùy chọn dòng lệnh, optparse.

+0

Không may nó phân tích cú pháp dòng lệnh * tùy chọn *, không * đối số * như dbr yêu cầu –

+0

Chính xác. Nó phù hợp nhất cho các đối số kiểu "-f 2 -v -z 55", theo như tôi có thể nói, trừ khi tôi thiếu một cái gì đó? – dbr

9

Mô-đun cmd có thể hoạt động tốt cho việc này.

Ví dụ:

import cmd 

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

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

Run nó:

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

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

(Cmd) 

Xem Python docs hoặc PyMOTW site để biết thêm.

0

Đây là đề xuất của tôi.

  1. Thay đổi ngữ pháp của bạn một chút.

  2. Sử dụng optparse.

Lý tưởng nhất cũng cho phép phân tích linh hoạt hơn, ví dụ,

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 

Sau đó, bạn có 1 hoặc 2 args: lệnh luôn là arg đầu tiên. Đó là đối số tùy chọn luôn là arg thứ hai.

Mọi thứ khác là tùy chọn, không theo thứ tự cụ thể.

Các vấn đề liên quan