Simple command line application in python - parse user input?

人盡茶涼 提交于 2019-12-08 06:33:40

问题


New to python here - I want to make a command line application where the user will type input I will parse it and execute some command - something in the lines of:

try:
    while True:
        input = raw_input('> ')
        # parse here
except KeyboardInterrupt:
    pass

The user is supposed to type commands like init /path/to/dir. Can I use argparse to parse those ? Is my way too crude ?


回答1:


arparse is a perfect solution for what you propose. The docs are well written and show dozens of example of how to invoke it simply. Keep in mind, it wants to read sys.argv by default, so when you invoke parse_args, you want to give it args (https://docs.python.org/2.7/library/argparse.html?highlight=argparse#the-parse-args-method).

The only downsize is argparse expects the items to be in "parameter" format, which means prefixed with dashes.

>>> import argparse
>>> parser = argparse.ArgumentParser(prog='PROG')
>>> parser.add_argument('-init', nargs=1)
>>> parser.parse_args('-init /path/to/something'.split())
Namespace(init="/path/to/something")



回答2:


You can take a look at the cmd lib: http://docs.python.org/library/cmd.html


If you want to parse by yourself, you can use split to tokenize the user input, and execute your commands based on the tokens, sort of like this:

try:
    while True:
        input = raw_input('> ')
        tokens = input.split()
        command = tokens[0]
        args = tokens[1:]
        if command == 'init':
            # perform init command
        elif command == 'blah':
            # perform other command


except KeyboardInterrupt:
    pass



回答3:


It depends on what you want to do, but you could have your script use ipython (interactive python). For instance:

    #!/bin/ipython -i
    def init(path_to_dir):
        print(path_to_dir)

Usage: after staring the script,

init("pathToFile.txt")

You are running in an interactive python session, so you get features like tab completion that would be difficult to implement manually. On the other hand, you are stuck with python syntax. It depends on your application.




回答4:


What I did was:

# main
parser = Parser('blah')
try:
    while True:
        # http://stackoverflow.com/a/17352877/281545
        cmd = shlex.split(raw_input('> ').strip())
        logging.debug('command line: %s', cmd)
        try:
            parser.parse(cmd)
        except SystemExit: # DUH http://stackoverflow.com/q/16004901/281545
            pass
except KeyboardInterrupt:
    pass

Where the parser:

class Parser(argparse.ArgumentParser):
    def __init__(self, desc, add_h=True):
        super(Parser, self).__init__(description=desc, add_help=add_h,
                                     formatter_class=argparse.
                                    ArgumentDefaultsHelpFormatter)
        # https://docs.python.org/dev/library/argparse.html#sub-commands
        self.subparsers = subparsers = self.add_subparsers(
            help='sub-command help')
        # http://stackoverflow.com/a/8757447/281545
        subparsers._parser_class = argparse.ArgumentParser
        from  watcher.commands import CMDS
        for cmd in CMDS: cmd()(subparsers)

    def parse(self, args):
        return self.parse_args(args)

And a command (CMDS=[watch.Watch]):

class Watch(Command):

    class _WatchAction(argparse.Action):
        def __call__(self, parser, namespace, values, option_string=None):
            # here is the actual logic of the command
            logging.debug('%r %r %r' % (namespace, values, option_string))
            setattr(namespace, self.dest, values)
            Sync.addObserver(path=values)

    CMD_NAME = 'watch'
    CMD_HELP = 'Watch a directory tree for changes'
    ARGUMENTS = {'path': Arg(hlp='Path to a directory to watch. May be '
                                  'relative or absolute', action=_WatchAction)}

where:

class Command(object):
    """A command given by the users - subclasses must define  the CMD_NAME,
    CMD_HELP and ARGUMENTS class fields"""

    def __call__(self, subparsers):
        parser_a = subparsers.add_parser(self.__class__.CMD_NAME,
                                         help=self.__class__.CMD_HELP)
        for dest, arg in self.__class__.ARGUMENTS.iteritems():
            parser_a.add_argument(dest=dest, help=arg.help, action=arg.action)
        return parser_a

class Arg(object):
    """Wrapper around cli arguments for a command"""

    def __init__(self, hlp=None, action='store'):
        self.help = hlp
        self.action = action

Only tried with one command so far so this is rather untested. I used the shlex and subparsers tips from comments. I had a look at the cmd module suggested by @jh314 but did not quite grok it - however I think it is the tool for the job - I am interested in an answer with code doing what I do but using the cmd module.



来源:https://stackoverflow.com/questions/25332925/simple-command-line-application-in-python-parse-user-input

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!