Python Language
Parsowanie argumentów wiersza poleceń
Szukaj…
Wprowadzenie
Większość narzędzi wiersza poleceń opiera się na argumentach przekazywanych do programu po jego uruchomieniu. Zamiast monitować o wprowadzenie, programy te oczekują ustawienia danych lub określonych flag (które stają się logicznymi). Dzięki temu zarówno użytkownik, jak i inne programy mogą uruchomić plik Python, przekazując mu dane podczas uruchamiania. Ta sekcja wyjaśnia i demonstruje implementację i użycie argumentów wiersza poleceń w Pythonie.
Witaj świecie w argparse
Poniższy program wita użytkownika. Wymaga jednego argumentu pozycyjnego, nazwy użytkownika, i można go również powitać.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('name',
help='name of user'
)
parser.add_argument('-g', '--greeting',
default='Hello',
help='optional alternate greeting'
)
args = parser.parse_args()
print("{greeting}, {name}!".format(
greeting=args.greeting,
name=args.name)
)
$ python hello.py --help
usage: hello.py [-h] [-g GREETING] name
positional arguments:
name name of user
optional arguments:
-h, --help show this help message and exit
-g GREETING, --greeting GREETING
optional alternate greeting
$ python hello.py world
Hello, world!
$ python hello.py John -g Howdy
Howdy, John!
Aby uzyskać więcej informacji, przeczytaj dokumentację argparse .
Podstawowy przykład z docopt
docopt obraca analizę argumentów wiersza poleceń na głowie. Zamiast analizować argumenty, wystarczy napisać ciąg użycia dla programu, a docopt analizuje ciąg użycia i używa go do wyodrębnienia argumentów wiersza poleceń.
"""
Usage:
script_name.py [-a] [-b] <path>
Options:
-a Print all the things.
-b Get more bees into the path.
"""
from docopt import docopt
if __name__ == "__main__":
args = docopt(__doc__)
import pprint; pprint.pprint(args)
Przykładowe przebiegi:
$ python script_name.py
Usage:
script_name.py [-a] [-b] <path>
$ python script_name.py something
{'-a': False,
'-b': False,
'<path>': 'something'}
$ python script_name.py something -a
{'-a': True,
'-b': False,
'<path>': 'something'}
$ python script_name.py -b something -a
{'-a': True,
'-b': True,
'<path>': 'something'}
Ustalanie wykluczających się argumentów za pomocą argparse
Jeśli chcesz, aby dwa lub więcej argumentów wykluczały się wzajemnie. Możesz użyć funkcji argparse.ArgumentParser.add_mutually_exclusive_group()
. W poniższym przykładzie może istnieć zarówno foo, jak i pasek, ale nie oba jednocześnie.
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-f", "--foo")
group.add_argument("-b", "--bar")
args = parser.parse_args()
print "foo = ", args.foo
print "bar = ", args.bar
Jeśli próbujesz uruchomić skrypt określający zarówno --foo
i --bar
argumenty, skrypt skarżą się z poniższym komunikatem.
error: argument -b/--bar: not allowed with argument -f/--foo
Używanie argumentów wiersza poleceń z argv
Ilekroć skrypt Python jest wywoływany z wiersza poleceń, użytkownik może podać dodatkowe argumenty wiersza poleceń, które zostaną przekazane do skryptu. Argumenty te będą dostępne dla programisty od zmiennej systemowej sys.argv
( „argv” to tradycyjna nazwa używana w większości języków programowania, a to oznacza „arg ument v ector”).
Zgodnie z konwencją pierwszym elementem na liście sys.argv
jest nazwa samego skryptu Python, a pozostałe elementy to tokeny przekazywane przez użytkownika podczas wywoływania skryptu.
# cli.py
import sys
print(sys.argv)
$ python cli.py
=> ['cli.py']
$ python cli.py fizz
=> ['cli.py', 'fizz']
$ python cli.py fizz buzz
=> ['cli.py', 'fizz', 'buzz']
Oto kolejny przykład użycia argv
. Najpierw usuwamy początkowy element pliku sys.argv, ponieważ zawiera on nazwę skryptu. Następnie łączymy pozostałe argumenty w jedno zdanie, a na końcu drukujemy to zdanie, poprzedzając nazwę aktualnie zalogowanego użytkownika (tak, aby emulował program czatu).
import getpass
import sys
words = sys.argv[1:]
sentence = " ".join(words)
print("[%s] %s" % (getpass.getuser(), sentence))
Algorytmem powszechnie stosowanym podczas „ręcznego” analizowania wielu argumentów pozycyjnych jest iteracja po liście sys.argv
. Jednym ze sposobów jest przejrzenie listy i usunięcie każdego jej elementu:
# reverse and copy sys.argv
argv = reversed(sys.argv)
# extract the first element
arg = argv.pop()
# stop iterating when there's no more args to pop()
while len(argv) > 0:
if arg in ('-f', '--foo'):
print('seen foo!')
elif arg in ('-b', '--bar'):
print('seen bar!')
elif arg in ('-a', '--with-arg'):
arg = arg.pop()
print('seen value: {}'.format(arg))
# get the next value
arg = argv.pop()
Komunikat o błędzie niestandardowego analizatora składni z argumentem argparse
Można tworzyć komunikaty o błędach analizatora składni zgodnie z potrzebami skryptu. Dzieje się tak dzięki funkcji argparse.ArgumentParser.error
. Poniższy przykład pokazuje skrypt --foo
użycie i komunikat błędu do stderr
gdy --foo
ale nie --bar
.
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--foo")
parser.add_argument("-b", "--bar")
args = parser.parse_args()
if args.foo and args.bar is None:
parser.error("--foo requires --bar. You did not specify bar.")
print "foo =", args.foo
print "bar =", args.bar
Zakładając, że nazwa twojego skryptu to sample.py i uruchamiamy: python sample.py --foo ds_in_fridge
Skrypt będzie narzekał na:
usage: sample.py [-h] [-f FOO] [-b BAR]
sample.py: error: --foo requires --bar. You did not specify bar.
Koncepcyjne grupowanie argumentów za pomocą argparse.add_argument_group ()
Kiedy tworzysz argparse ArgumentParser () i uruchamiasz swój program za pomocą „-h”, pojawia się komunikat o automatycznym użyciu wyjaśniający, z jakimi argumentami możesz uruchomić swoje oprogramowanie. Domyślnie argumenty pozycyjne i argumenty warunkowe są podzielone na dwie kategorie, na przykład tutaj jest mały skrypt (example.py) i dane wyjściowe po uruchomieniu python example.py -h
.
import argparse
parser = argparse.ArgumentParser(description='Simple example')
parser.add_argument('name', help='Who to greet', default='World')
parser.add_argument('--bar_this')
parser.add_argument('--bar_that')
parser.add_argument('--foo_this')
parser.add_argument('--foo_that')
args = parser.parse_args()
usage: example.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
[--foo_this FOO_THIS] [--foo_that FOO_THAT]
name
Simple example
positional arguments:
name Who to greet
optional arguments:
-h, --help show this help message and exit
--bar_this BAR_THIS
--bar_that BAR_THAT
--foo_this FOO_THIS
--foo_that FOO_THAT
Istnieją sytuacje, w których chcesz podzielić argumenty na dalsze sekcje pojęciowe, aby pomóc użytkownikowi. Na przykład możesz chcieć mieć wszystkie opcje wprowadzania w jednej grupie, a wszystkie opcje formowania wyników w innej. Powyższy przykład można dostosować, aby oddzielić --foo_*
od argumentów --bar_*
.
import argparse
parser = argparse.ArgumentParser(description='Simple example')
parser.add_argument('name', help='Who to greet', default='World')
# Create two argument groups
foo_group = parser.add_argument_group(title='Foo options')
bar_group = parser.add_argument_group(title='Bar options')
# Add arguments to those groups
foo_group.add_argument('--bar_this')
foo_group.add_argument('--bar_that')
bar_group.add_argument('--foo_this')
bar_group.add_argument('--foo_that')
args = parser.parse_args()
Który tworzy to wyjście, gdy uruchamiany jest python example.py -h
:
usage: example.py [-h] [--bar_this BAR_THIS] [--bar_that BAR_THAT]
[--foo_this FOO_THIS] [--foo_that FOO_THAT]
name
Simple example
positional arguments:
name Who to greet
optional arguments:
-h, --help show this help message and exit
Foo options:
--bar_this BAR_THIS
--bar_that BAR_THAT
Bar options:
--foo_this FOO_THIS
--foo_that FOO_THAT
Zaawansowany przykład z docopt i docopt_dispatch
Podobnie jak w przypadku docopt, w [docopt_dispatch] tworzysz swoje --help
w zmiennej __doc__
modułu punktu wejścia. Tam wywołujesz dispatch
z ciągiem doc jako argumentem, aby mógł on nad nim analizować parser.
Po wykonaniu tej czynności zamiast ręcznej obsługi argumentów (która zwykle kończy się na wysokiej cyklicznej strukturze if / else), pozostawiasz to do wysyłki, podając tylko sposób obsługi zestawu argumentów.
Do tego służy dekorator dispatch.on
: podajesz mu argument lub sekwencję argumentów, które powinny wywołać funkcję, a funkcja ta zostanie wykonana z pasującymi wartościami jako parametrami.
"""Run something in development or production mode.
Usage: run.py --development <host> <port>
run.py --production <host> <port>
run.py items add <item>
run.py items delete <item>
"""
from docopt_dispatch import dispatch
@dispatch.on('--development')
def development(host, port, **kwargs):
print('in *development* mode')
@dispatch.on('--production')
def development(host, port, **kwargs):
print('in *production* mode')
@dispatch.on('items', 'add')
def items_add(item, **kwargs):
print('adding item...')
@dispatch.on('items', 'delete')
def items_delete(item, **kwargs):
print('deleting item...')
if __name__ == '__main__':
dispatch(__doc__)