问题
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