Jaki jest najlepszy sposób na analizę argumentów wiersza poleceń? [zamknięte]
chcesz poprawić to pytanie? Update the question so it edytując ten post.
Zamknięte 1 rok temu .
Popraw to pytanieJaki jest najprostszy, tersest i większość elastyczna metoda do parsowania argumentów linii poleceń Pythona?
15 answers
Ta odpowiedź sugeruje optparse
, która jest odpowiednia dla starszych wersji Pythona. Dla Pythona 2.7 i nowszych, argparse
zastępuje optparse
. Zobacz ta odpowiedź aby uzyskać więcej informacji.
Jak zauważyli inni, lepiej wybrać optparse zamiast getopt. getopt jest w zasadzie mapowaniem jeden do jednego standardowych funkcji biblioteki getopt(3) C i nie jest bardzo łatwy w użyciu.
Optparse, choć jest nieco bardziej wyrazisty, jest znacznie lepiej zorganizowany i prostszy do / align = "left" /
Oto typowy wiersz, aby dodać opcję do parsera:
parser.add_option('-q', '--query',
action="store", dest="query",
help="query string", default="spam")
To mówi samo za siebie; w czasie przetwarzania, przyjmuje jako opcje-q lub --query, przechowuje argument w atrybucie zwanym query i ma domyślną wartość, jeśli go nie podasz. Jest to również samodokumentujące się w tym, że deklarujesz argument help (który będzie używany podczas uruchamiania z-h/--help) właśnie tam z opcją.
Zwykle analizujesz swoje argumenty z:
options, args = parser.parse_args()
Domyślnie parsuje standardowe argumenty przekazywane do skryptu (sys.argv[1:])
Opcje.zapytanie zostanie następnie ustawione na wartość przekazaną do skryptu.
Tworzysz parser po prostu wykonując
parser = optparse.OptionParser()
To wszystko, czego potrzebujesz. Oto kompletny skrypt Pythona, który to pokazuje:
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 linii Pythona, które pokazują podstawy.
Save it in sample.py i uruchom go raz z
python sample.py
I raz z
python sample.py --query myquery
Poza tym przekonasz się, że optparse jest bardzo łatwy do rozszerzenia. W jednym z moich projektów stworzyłem klasę poleceń, która pozwala na łatwe zagnieżdżanie podpowiedzi w drzewie poleceń. Używa optparse mocno do łączenia poleceń. Nie jest to coś, co mogę łatwo wyjaśnić w kilku linijkach, ale zapraszam do przeglądania w moim repozytorium dla głównej klasy, a także klasy, która go używa i parsera opcji
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 12:34:47
argparse
to jest droga. Oto krótkie podsumowanie, jak go używać:
1) Initialize
import argparse
# Instantiate the parser
parser = argparse.ArgumentParser(description='Optional app description')
2) Dodaj Argumenty
# 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) Parse
args = parser.parse_args()
4) Access
print("Argument values:")
print(args.pos_arg)
print(args.opt_pos_arg)
print(args.opt_arg)
print(args.switch)
5) Wartości Kontrolne
if args.pos_arg > 10:
parser.error("pos_arg cannot be larger than 10")
Użycie
Prawidłowe użycie:
$ ./app 1 2 --opt_arg 3 --switch
Argument values:
1
2
3
True
Błędne argumenty:
$ ./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
Pełna pomoc:
$ ./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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-02 11:00:22
Używanie docopt
Od 2012 roku istnieje bardzo łatwy, potężny i naprawdę fajny moduł do parsowania argumentów o nazwie docopt. Oto przykład zaczerpnięty z jego dokumentacji:
"""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)
Więc to jest to: 2 linie kodu plus Twój ciąg doc, który jest niezbędny, a twoje argumenty są przetwarzane i dostępne w obiekcie arguments.
Używanie Pythona-fire
Od 2017 roku istnieje kolejny fajny moduł o nazwie python-fire. Może Wygeneruj interfejs CLI dla Twojego kodu, wykonując zero parsowanie argumentów. Oto prosty przykład z dokumentacji (ten mały program wyświetla funkcję double
w wierszu poleceń):
import fire
class Calculator(object):
def double(self, number):
return 2 * number
if __name__ == '__main__':
fire.Fire(Calculator)
Z linii poleceń można uruchomić:
> calculator.py double 10
20
> calculator.py double --number=15
30
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-08-07 13:23:45
Nowy sposób hip jest argparse
z tych Powodów. argparse > optparse > getopt
Update: od py2.7 argparse jest częścią biblioteki standardowej i optparse jest przestarzały.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-07-31 21:45:52
Wolę Kliknij . Zawiera opcje zarządzania i pozwala " (...) tworzenie pięknych interfejsów wiersza poleceń w sposób komponowalny z tak małą ilością kodu, jak to konieczne".
Oto przykład użycia:
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()
Automatycznie generuje ładnie sformatowane strony pomocy:
$ 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.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-02-03 20:36:48
Prawie każdy używa getopt
Oto przykładowy kod doc:
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
Jednym słowem, oto jak to działa.
Masz dwa rodzaje opcji. Tych, którzy przyjmują argumenty, oraz tych, którzy są tak jak przełączniki.
sys.argv
jest w zasadzie twoim char** argv
W C. tak jak w C pomijasz pierwszy element, który jest nazwą Twojego programu i analizujesz tylko argumenty: sys.argv[1:]
Getopt.getopt
przetworzy go zgodnie z regułą ty się kłócisz.
"ho:v"
Oto krótkie argumenty: -ONELETTER
. :
oznacza, że -o
przyjmuje jeden argument.
Wreszcie ["help", "output="]
opisuje długie argumenty (--MORETHANONELETTER
).
=
po wyjściu ponownie oznacza, że output akceptuje jeden argument.
Wynikiem jest lista par (opcja,argument)
Jeśli opcja nie akceptuje żadnego argumentu (jak --help
tutaj), część arg
jest pustym łańcuchem znaków.
Następnie Zwykle chcesz zapętlić tę listę i przetestować nazwa opcji jak w przykładzie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-16 17:36:53
Użyj optparse
, który pochodzi z biblioteki standardowej. Na przykład:
#!/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()
Źródło: używanie Pythona do tworzenia uniksowych narzędzi wiersza poleceń
Jednak od Pythona 2.7 optparse jest przestarzały, zobacz: Dlaczego używać argparse zamiast optparse?
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:59
Lightweight command line argument defaults
Chociaż argparse
jest świetny i jest właściwą odpowiedzią dla w pełni udokumentowanych przełączników wiersza poleceń i zaawansowanych funkcji, możesz użyć domyślnych argumentów funkcji, aby obsłużyć proste argumenty pozycyjne w bardzo prosty sposób.
import sys
def get_args(name='default', first='a', second=2):
return first, int(second)
first, second = get_args(*sys.argv)
print first, second
Argument 'name' przechwytuje nazwę skryptu i nie jest używany. Wynik testu wygląda tak:
> ./test.py
a 2
> ./test.py A
A 2
> ./test.py A 20
A 20
Dla prostych skryptów, w których chcę tylko domyślnych wartości, uważam to za całkiem wystarczy. Możesz również dodać pewien rodzaj przymusu w zwracanych wartościach lub wartości wiersza poleceń będą ciągami znaków.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-08 12:44:34
Na wszelki wypadek, może to pomóc, jeśli potrzebujesz pobrać argumenty unicode na Win32 (2K, XP itp.):
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()
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-21 14:59:54
Kod Argparse może być dłuższy niż rzeczywisty kod implementacyjny!
To jest problem, który znalazłem z najbardziej popularnych opcji parsowania argumentów jest to, że jeśli parametry są tylko skromne, kod do ich udokumentowania staje się nieproporcjonalnie duży dla korzyści, które zapewniają.
Względną nowością do sceny parsowania argumentów (myślę) jest plac .
To sprawia, że niektóre uznane kompromisów z argparse, ale używa wbudowanej dokumentacji i owija się po prostu wokół main()
type function function:
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-05 07:17:58
Wolę optparse niż getopt. Jest to bardzo deklaratywne: podajesz mu nazwy opcji i efekty, które powinny mieć (np. ustawiając pole logiczne), a to oddaje Ci słownik wypełniony zgodnie z Twoimi specyfikacjami.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-21 15:22:20
Myślę, że najlepszym sposobem na większe projekty jest optparse, ale jeśli szukasz łatwego sposobu, Może http://werkzeug.pocoo.org/documentation/script to coś dla Ciebie.
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()
Więc w zasadzie każda funkcja action_* jest wystawiona na działanie linii poleceń i ładną wiadomość pomoc jest generowana za darmo.
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-27 19:41:22
Consoleargs Jest bardzo łatwy w użyciu. Zobacz też:
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()
Teraz w konsoli:
% 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''
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-06-30 05:43:02
Oto metoda, a nie biblioteka, która wydaje się działać dla mnie.
Cele tutaj są zwięzłe, każdy argument parsowany pojedynczą linią, linia args dla czytelności, kod jest prosty i nie zależy od żadnych specjalnych modułów( tylko os + sys), ostrzega o brakujących lub nieznanych argumentów wdzięcznie, używa prostej pętli for / range() i działa w Pythonie 2.x i 3.x
Pokazane są dwa znaczniki przełączania (- d,- v) i dwie wartości kontrolowane przez argumenty (- i xxx I-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))
Celem nextarg() jest zwrócenie następnego argumentu podczas sprawdzania brakujących danych, a 'skip' pomija pętlę, gdy jest używana NextArg (), zachowując flagę parsującą do jednej linii.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-04-09 17:43:18
Rozszerzyłem podejście Erco, aby umożliwić wymagane argumenty pozycyjne i argumenty opcjonalne. Powinny one poprzedzać-d, - v itd. argumenty.
Argumenty pozycyjne i opcjonalne można pobrać odpowiednio za pomocą PosArg(i) i OptArg(i, domyślnie). Po znalezieniu opcjonalnego argumentu pozycja początkowa wyszukiwania opcji (np.-i)jest przesuwana o 1 do przodu, aby uniknąć 'nieoczekiwanego' fatalnego wyniku.
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)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-24 12:32:43