Respostas:
Esta resposta sugere o optparse
que é apropriado para versões mais antigas do Python. Para Python 2.7 e superior, argparse
substitui optparse
. Veja esta resposta para mais informações.
Como outras pessoas apontaram, é melhor você optar pelo oposto do que pelo getopt. O getopt é praticamente um mapeamento individual das funções padrão da biblioteca getopt (3) C, e não é muito fácil de usar.
O optparse, embora seja um pouco mais detalhado, é muito melhor estruturado e mais simples de estender mais tarde.
Aqui está uma linha típica para adicionar uma opção ao seu analisador:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
Ele praticamente fala por si; no tempo de processamento, ele aceitará -q ou --query como opções, armazenará o argumento em um atributo chamado query e terá um valor padrão se você não o especificar. Também é auto-documentado, na medida em que você declara o argumento de ajuda (que será usado quando executado com -h / - help) ali mesmo com a opção
Geralmente você analisa seus argumentos com:
options, args = parser.parse_args()
Por padrão, isso analisará os argumentos padrão passados para o script (sys.argv [1:])
options.query será então definido como o valor que você passou para o script.
Você cria um analisador simplesmente fazendo
parser = optparse.OptionParser()
Estes são todos os princípios básicos que você precisa. Aqui está um script Python completo que mostra isso:
import optparse
parser = optparse.OptionParser()
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
options, args = parser.parse_args()
print 'Query string:', options.query
5 linhas de python que mostram o básico.
Salve-o em sample.py e execute-o uma vez com
python sample.py
e uma vez com
python sample.py --query myquery
Além disso, você descobrirá que o optparse é muito fácil de estender. Em um dos meus projetos, criei uma classe Command que permite aninhar subcomandos em uma árvore de comandos facilmente. Ele usa optparse fortemente para encadear comandos juntos. Não é algo que eu possa explicar facilmente em poucas linhas, mas fique à vontade para procurar no meu repositório a classe principal, bem como uma classe que o use e o analisador de opções
-mcProfile -o program.prof
mas o agrparcer está capturando esses argumentos, como passar esses argumentos para python exe ???
argparse
é o caminho a percorrer. Aqui está um breve resumo de como usá-lo:
1) Inicializar
import argparse
# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')
2) Adicionar argumentos
# Required positional argument
parser.add_argument('pos_arg', type=int,
help='A required integer positional argument')
# Optional positional argument
parser.add_argument('opt_pos_arg', type=int, nargs='?',
help='An optional integer positional argument')
# Optional argument
parser.add_argument('--opt_arg', type=int,
help='An optional integer argument')
# Switch
parser.add_argument('--switch', action='store_true',
help='A boolean switch')
3) Analisar
args = parser.parse_args()
4) Acesso
print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)
5) Verificar valores
if args.pos_arg > 10:
parser.error("pos_arg cannot be larger than 10")
Uso correto:
$ ./app 1 2 --opt_arg 3 --switch
Argument values:
1
2
3
True
Argumentos incorretos:
$ ./app foo 2 --opt_arg 3 --switch
usage: convert [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
app: error: argument pos_arg: invalid int value: 'foo'
$ ./app 11 2 --opt_arg 3
Argument values:
11
2
3
False
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
convert: error: pos_arg cannot be larger than 10
Ajuda completa:
$ ./app -h
usage: app [-h] [--opt_arg OPT_ARG] [--switch] pos_arg [opt_pos_arg]
Optional app description
positional arguments:
pos_arg A required integer positional argument
opt_pos_arg An optional integer positional argument
optional arguments:
-h, --help show this help message and exit
--opt_arg OPT_ARG An optional integer argument
--switch A boolean switch
Desde 2012, existe um módulo muito fácil, poderoso e muito interessante para análise de argumentos chamado docopt . Aqui está um exemplo retirado de sua documentação:
"""Naval Fate.
Usage:
naval_fate.py ship new <name>...
naval_fate.py ship <name> move <x> <y> [--speed=<kn>]
naval_fate.py ship shoot <x> <y>
naval_fate.py mine (set|remove) <x> <y> [--moored | --drifting]
naval_fate.py (-h | --help)
naval_fate.py --version
Options:
-h --help Show this screen.
--version Show version.
--speed=<kn> Speed in knots [default: 10].
--moored Moored (anchored) mine.
--drifting Drifting mine.
"""
from docopt import docopt
if __name__ == '__main__':
arguments = docopt(__doc__, version='Naval Fate 2.0')
print(arguments)
Então é isso: duas linhas de código, mais a sua sequência de documentos, que é essencial e você obtém seus argumentos analisados e disponíveis no seu objeto de argumentos.
Desde 2017, há outro módulo interessante chamado python-fire . Ele pode gerar uma interface CLI para seu código, sem a análise de argumentos. Aqui está um exemplo simples da documentação (este pequeno programa expõe a função double
à linha de comando):
import fire
class Calculator(object):
def double(self, number):
return 2 * number
if __name__ == '__main__':
fire.Fire(Calculator)
Na linha de comando, você pode executar:
> calculator.py double 10
20
> calculator.py double --number=15
30
A nova maneira moderna é argparse
por esses motivos. argparse> optparse> getopt
update: A partir do py2.7, o argparse faz parte da biblioteca padrão e o optparse está obsoleto.
Eu prefiro o Click . Ele abstrai as opções de gerenciamento e permite "(...) criar belas interfaces de linha de comando de uma maneira composível, com o mínimo de código necessário".
Aqui está um exemplo de uso:
import click
@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',
help='The person to greet.')
def hello(count, name):
"""Simple program that greets NAME for a total of COUNT times."""
for x in range(count):
click.echo('Hello %s!' % name)
if __name__ == '__main__':
hello()
Também gera automaticamente páginas de ajuda bem formatadas:
$ python hello.py --help
Usage: hello.py [OPTIONS]
Simple program that greets NAME for a total of COUNT times.
Options:
--count INTEGER Number of greetings.
--name TEXT The person to greet.
--help Show this message and exit.
Praticamente todo mundo está usando getopt
Aqui está o código de exemplo para o documento:
import getopt, sys
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "ho:v", ["help", "output="])
except getopt.GetoptError:
# print help information and exit:
usage()
sys.exit(2)
output = None
verbose = False
for o, a in opts:
if o == "-v":
verbose = True
if o in ("-h", "--help"):
usage()
sys.exit()
if o in ("-o", "--output"):
output = a
Então, em uma palavra, aqui está como isso funciona.
Você tem dois tipos de opções. Aqueles que estão recebendo argumentos e aqueles que são como interruptores.
sys.argv
é praticamente seu char** argv
em C. Como em C, você pula o primeiro elemento, que é o nome do seu programa, e analisa apenas os argumentos:sys.argv[1:]
Getopt.getopt
irá analisá-lo de acordo com a regra que você fornecer no argumento.
"ho:v"
aqui descreve as curtas argumentos: -ONELETTER
. O :
meio que -o
aceita um argumento.
Finalmente ["help", "output="]
descreve argumentos longos ( --MORETHANONELETTER
). A =
saída posterior significa novamente que a saída aceita um argumento.
O resultado é uma lista de pares (opção, argumento)
Se uma opção não aceita nenhum argumento (como --help
aqui), a arg
parte é uma sequência vazia. Você geralmente deseja fazer um loop nesta lista e testar o nome da opção como no exemplo.
Espero que isso tenha ajudado.
getopt
nas versões mais recentes do Python, essa resposta ficou desatualizada.
getopt
ainda não está obsoleto… Mas sua documentação afirma que ele é principalmente fornecido para usuários familiarizados com a getopt()
função C e reconhece que para outros usuários argparse
pode ser uma solução melhor, permitindo "escrever menos código e obter melhor ajuda e mensagens de erro ".
Uso optparse
que acompanha a biblioteca padrão. Por exemplo:
#!/usr/bin/env python
import optparse
def main():
p = optparse.OptionParser()
p.add_option('--person', '-p', default="world")
options, arguments = p.parse_args()
print 'Hello %s' % options.person
if __name__ == '__main__':
main()
Fonte: Usando o Python para criar ferramentas de linha de comando UNIX
No entanto, a partir do Python 2.7 optparse está obsoleta, consulte: Por que usar argparse em vez de optparse?
Caso precise, isso pode ajudar se você precisar pegar argumentos unicode no Win32 (2K, XP, etc.):
from ctypes import *
def wmain(argc, argv):
print argc
for i in argv:
print i
return 0
def startup():
size = c_int()
ptr = windll.shell32.CommandLineToArgvW(windll.kernel32.GetCommandLineW(), byref(size))
ref = c_wchar_p * size.value
raw = ref.from_address(ptr)
args = [arg for arg in raw]
windll.kernel32.LocalFree(ptr)
exit(wmain(len(args), args))
startup()
Padrões de argumento de linha de comando leve
Embora argparse
seja ótimo e seja a resposta certa para opções de linha de comando totalmente documentadas e recursos avançados, você pode usar os padrões de argumento de função para manipular argumentos posicionais diretos com muita simplicidade.
import sys
def get_args(name='default', first='a', second=2):
return first, int(second)
first, second = get_args(*sys.argv)
print first, second
O argumento 'name' captura o nome do script e não é usado. A saída de teste é assim:
> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20
Para scripts simples em que eu apenas quero alguns valores padrão, acho isso suficiente. Você também pode querer incluir algum tipo de coerção nos valores de retorno ou os valores da linha de comando serão cadeias de caracteres.
Eu prefiro optar por obter. É muito declarativo: você diz os nomes das opções e os efeitos que elas devem ter (por exemplo, definindo um campo booleano) e fornece um dicionário preenchido de acordo com suas especificações.
Acho que a melhor maneira para projetos maiores é a opção optparse, mas se você estiver procurando uma maneira fácil, talvez http://werkzeug.pocoo.org/documentation/script seja algo para você.
from werkzeug import script
# actions go here
def action_foo(name=""):
"""action foo does foo"""
pass
def action_bar(id=0, title="default title"):
"""action bar does bar"""
pass
if __name__ == '__main__':
script.run()
Então, basicamente, toda função action_ * é exposta à linha de comando e uma boa mensagem de ajuda é gerada gratuitamente.
python foo.py
usage: foo.py <action> [<options>]
foo.py --help
actions:
bar:
action bar does bar
--id integer 0
--title string default title
foo:
action foo does foo
--name string
declarative_parser
. Obviamente, se alguém estiver trabalhando com o werkzeug, talvez seja melhor manter o arquivo werkzung.script
. De qualquer forma, sou um grande fã dessa abordagem.
O código Argparse pode ser maior que o código de implementação real!
Esse é um problema que acho que nas opções de análise de argumento mais populares é que, se seus parâmetros são modestos, o código para documentá-los se torna desproporcionalmente grande para o benefício que eles oferecem.
Um recém-chegado relativo à cena de análise de argumentos (eu acho) é plac .
Ele faz algumas trocas reconhecidas com argparse, mas usa a documentação embutida e envolve simplesmente a main()
função de função type:
def main(excel_file_path: "Path to input training file.",
excel_sheet_name:"Name of the excel sheet containing training data including columns 'Label' and 'Description'.",
existing_model_path: "Path to an existing model to refine."=None,
batch_size_start: "The smallest size of any minibatch."=10.,
batch_size_stop: "The largest size of any minibatch."=250.,
batch_size_step: "The step for increase in minibatch size."=1.002,
batch_test_steps: "Flag. If True, show minibatch steps."=False):
"Train a Spacy (http://spacy.io/) text classification model with gold document and label data until the model nears convergence (LOSS < 0.5)."
pass # Implementation code goes here!
if __name__ == '__main__':
import plac; plac.call(main)
consoleargs merece ser mencionado aqui. É muito fácil de usar. Confira:
from consoleargs import command
@command
def main(url, name=None):
"""
:param url: Remote URL
:param name: File name
"""
print """Downloading url '%r' into file '%r'""" % (url, name)
if __name__ == '__main__':
main()
Agora no console:
% python demo.py --help
Usage: demo.py URL [OPTIONS]
URL: Remote URL
Options:
--name -n File name
% python demo.py http://www.google.com/
Downloading url ''http://www.google.com/'' into file 'None'
% python demo.py http://www.google.com/ --name=index.html
Downloading url ''http://www.google.com/'' into file ''index.html''
Aqui está um método, não uma biblioteca, que parece funcionar para mim.
Os objetivos aqui devem ser concisos, cada argumento analisado por uma única linha, os argumentos alinhados para facilitar a leitura, o código é simples e não depende de nenhum módulo especial (apenas os + sys), alerta sobre argumentos ausentes ou desconhecidos normalmente , use um loop for / range () simples e funcione no python 2.xe 3.x
São mostrados dois sinalizadores de alternância (-d, -v) e dois valores controlados pelos argumentos (-i xxx e -o xxx).
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
# Parse command line
skip = 0
for i in range(1, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("%d,%d,%s,%s" % (debug,verbose,infile,outfile))
O objetivo do NextArg () é retornar o próximo argumento enquanto verifica a falta de dados, e 'skip' ignora o loop quando o NextArg () é usado, mantendo o sinalizador analisando em um só forro.
Estendi a abordagem de Erco para permitir argumentos posicionais necessários e argumentos opcionais. Estes devem preceder os argumentos -d, -v etc.
Argumentos posicionais e opcionais podem ser recuperados com PosArg (i) e OptArg (i, padrão), respectivamente. Quando um argumento opcional é encontrado, a posição inicial da busca por opções (por exemplo, -i) é movida 1 adiante, para evitar causar um fatal 'inesperado'.
import os,sys
def HelpAndExit():
print("<<your help output goes here>>")
sys.exit(1)
def Fatal(msg):
sys.stderr.write("%s: %s\n" % (os.path.basename(sys.argv[0]), msg))
sys.exit(1)
def NextArg(i):
'''Return the next command line argument (if there is one)'''
if ((i+1) >= len(sys.argv)):
Fatal("'%s' expected an argument" % sys.argv[i])
return(1, sys.argv[i+1])
def PosArg(i):
'''Return positional argument'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
return sys.argv[i]
def OptArg(i, default):
'''Return optional argument (if there is one)'''
if i >= len(sys.argv):
Fatal("'%s' expected an argument" % sys.argv[i])
if sys.argv[i][:1] != '-':
return True, sys.argv[i]
else:
return False, default
### MAIN
if __name__=='__main__':
verbose = 0
debug = 0
infile = "infile"
outfile = "outfile"
options_start = 3
# --- Parse two positional parameters ---
n1 = int(PosArg(1))
n2 = int(PosArg(2))
# --- Parse an optional parameters ---
present, a3 = OptArg(3,50)
n3 = int(a3)
options_start += int(present)
# --- Parse rest of command line ---
skip = 0
for i in range(options_start, len(sys.argv)):
if not skip:
if sys.argv[i][:2] == "-d": debug ^= 1
elif sys.argv[i][:2] == "-v": verbose ^= 1
elif sys.argv[i][:2] == "-i": (skip,infile) = NextArg(i)
elif sys.argv[i][:2] == "-o": (skip,outfile) = NextArg(i)
elif sys.argv[i][:2] == "-h": HelpAndExit()
elif sys.argv[i][:1] == "-": Fatal("'%s' unknown argument" % sys.argv[i])
else: Fatal("'%s' unexpected" % sys.argv[i])
else: skip = 0
print("Number 1 = %d" % n1)
print("Number 2 = %d" % n2)
print("Number 3 = %d" % n3)
print("Debug = %d" % debug)
print("verbose = %d" % verbose)
print("infile = %s" % infile)
print("outfile = %s" % outfile)