Przegląd
Ponieważ Python jest bardzo popularnym językiem programowania, a także obsługuje większość systemów operacyjnych i wiele bibliotek, które ułatwiają przetwarzanie argumentów w wierszu poleceń, stał się powszechnie używany do tworzenia narzędzi wiersza poleceń do wielu celów. Narzędzia te mogą obejmować zarówno proste aplikacje CLI, jak i te bardziej złożone, jak AWS awscli narzędziem.
Złożone narzędzia, takie jak to, są zwykle kontrolowane przez użytkownika za pośrednictwem argumenty wiersza poleceń, co pozwala użytkownikowi używać określonych poleceń, ustawiać opcje i nie tylko. Na przykład te opcje mogą nakazać narzędziu wygenerowanie dodatkowych informacji, odczytanie danych z określonego źródła lub wysłanie danych wyjściowych do określonej lokalizacji.
Ogólnie rzecz biorąc, argumenty są przekazywane do narzędzi CLI w różny sposób, w zależności od systemu operacyjnego:
- Uniksopodobny:
-
po którym następuje litera np-h
lub--
po którym następuje słowo np--help
- Windows:
/
po którym następuje litera lub słowo, np/help
Te różne podejścia istnieją ze względów historycznych. Wiele programów w systemach uniksopodobnych obsługuje zarówno notację z pojedynczą, jak i podwójną kreską. Notacja z pojedynczą kreską jest najczęściej używana z opcjami jednoliterowymi, podczas gdy podwójne myślniki przedstawiają bardziej czytelną listę opcji, co jest szczególnie przydatne w przypadku złożonych opcji, które muszą być bardziej wyraźne.
Note: W tym artykule skupimy się wyłącznie na uniksopodobnym formacie -
i --
.
Należy pamiętać, że zarówno nazwa, jak i znaczenie argumentu są specyficzne dla programu — nie ma ogólnej definicji poza kilkoma powszechnymi konwencjami, takimi jak --help
aby uzyskać więcej informacji na temat korzystania z narzędzia. Jako twórca skryptu w języku Python to Ty decydujesz, jakie argumenty podać dzwoniącemu i co on zrobi. To wymaga właściwej oceny.
Wraz ze wzrostem listy dostępnych argumentów Twój kod będzie stawał się coraz bardziej złożony, próbując je dokładnie przeanalizować. Na szczęście w Pythonie dostępnych jest wiele bibliotek, które mogą ci w tym pomóc. Omówimy kilka najpopularniejszych rozwiązań, od „zrób to sam” z sys.argv
, do podejścia „gotowe dla Ciebie” z argparse
.
Obsługa argumentów wiersza poleceń za pomocą Pythona
Python 3+ i otaczający go ekosystem obsługuje wiele różnych sposobów obsługi argumentów wiersza poleceń. Tam są wiele biblioteki ułatwiające analizowanie argumentów wiersza poleceń.
Wbudowanym sposobem jest użycie sys
moduł. Pod względem nazw i sposobu użycia odnosi się bezpośrednio do biblioteki C (libc
).
Drugi sposób to tzw getopt
moduł, który obsługuje zarówno krótkie, jak i długie opcje, w tym ocenę wartości parametrów.
Połączenia moduł argparse, który wywodzi się z optparse
moduł (dostępny do Pythona 2.7).
Połączenia docopt
moduł, tj dostępne na GitHub, umożliwia również taką samą funkcjonalność.
Ostatnio, absl
biblioteka również zyskuje na popularności, jako sposób na zastąpienie optparse
i getopt()
.
Każdy z tych sposobów ma swoje zalety i wady, dlatego warto ocenić każdy z nich, aby zobaczyć, który najlepiej odpowiada Twoim potrzebom.
Moduł sys
Jest to podstawowy moduł, który był dostarczany z Pythonem od samego początku. Przyjmuje bardzo podobne podejście do używania biblioteki C argc
/argv
aby uzyskać dostęp do argumentów. The moduł sys implementuje argumenty wiersza poleceń w prostej strukturze listy o nazwie sys.argv
.
Każdy element listy reprezentuje pojedynczy argument. Pierwsza pozycja na liście,
sys.argv[0]
, to nazwa skryptu Pythona. Reszta elementów listy,sys.argv[1]
dosys.argv[n]
, to argumenty wiersza poleceń od 2 do n.
Jako ogranicznik między argumentami używana jest spacja. Wartości argumentów zawierające spację muszą być otoczone cudzysłowami, aby mogły zostać poprawnie przeanalizowane sys
.
odpowiednik argc
to po prostu liczba elementów na liście. Aby uzyskać tę wartość, użyj metody Python len()
operator. Pokażemy to później w przykładzie kodu.
Drukowanie pierwszego argumentu CLI
W tym pierwszym przykładzie nasz skrypt określi sposób, w jaki został wywołany. Ta informacja jest przechowywana w pierwszym argumencie wiersza poleceń, indeksowanym przez 0. Poniższy kod pokazuje, jak uzyskać nazwę skryptu Pythona:
import sys
print("The script has the name %s" % (sys.argv[0])
Zapisz ten kod w pliku o nazwie arguments-program-name.py
, a następnie wywołaj go, jak pokazano poniżej. Dane wyjściowe są następujące i zawierają nazwę pliku, w tym jego pełną ścieżkę:
$ python arguments-program-name.py
The script has the name arguments-program-name.py
$ python /home/user/arguments-program-name.py
The script has the name /home/user/arguments-program-name.py
Jak widać z drugiego wywołania powyżej, otrzymujemy nie tylko nazwę pliku Pythona, ale także pełną ścieżkę używaną do jego wywołania.
Liczenie liczby argumentów
W tym drugim przykładzie po prostu policzymy liczbę argumentów wiersza poleceń za pomocą wbudowanego len()
Metoda. sys.argv
to lista, którą musimy zbadać. W poniższym kodzie otrzymujemy liczbę argumentów, a następnie odejmujemy 1, ponieważ jeden z tych argumentów (tj. pierwszy) jest zawsze ustawiany jako nazwa pliku, co nie zawsze jest dla nas przydatne. Zatem rzeczywista liczba argumentów przekazanych przez użytkownika wynosi len(sys.argv) - 1
:
import sys
arguments = len(sys.argv) - 1
print ("The script is called with %i arguments" % (arguments))
Zapisz i nazwij ten plik arguments-count.py. Poniżej przedstawiono kilka przykładów wywołania tego skryptu. Obejmuje to trzy różne scenariusze:
- Wywołanie bez dalszych argumentów wiersza poleceń
- Wywołanie z dwoma argumentami
- Wywołanie z dwoma argumentami, gdzie drugim argumentem jest ciąg znaków ujęty w cudzysłów zawierający spację
$ python arguments-count.py
The script is called with 0 arguments
$ python arguments-count.py --help me
The script is called with 2 arguments
$ python arguments-count.py --option "long string"
The script is called with 2 arguments
Iteracja poprzez argumenty
Nasz trzeci przykład wyświetla każdy pojedynczy argument wysłany do skryptu Pythona, z wyjątkiem samej nazwy programu. Dlatego przechodzimy przez argumenty wiersza poleceń zaczynające się od Dopiero element listy. Przypomnij sobie, że jest to indeks 1, ponieważ listy są oparte na 0 w Pythonie:
import sys
arguments = len(sys.argv) - 1
position = 1
while (arguments >= position):
print ("Parameter %i: %s" % (position, sys.argv[position]))
position = position + 1
Poniżej wywołujemy nasz kod, który został zapisany do pliku arguments-output.py. Podobnie jak w naszym poprzednim przykładzie, dane wyjściowe ilustrują trzy różne wywołania:
- Wezwanie bez żadnych argumentów
- Wywołanie z dwoma argumentami
- Wywołanie z dwoma argumentami, gdzie drugim argumentem jest ciąg znaków ujęty w cudzysłów zawierający spację
$ python arguments-output.py
$ python arguments-output.py --help me
Parameter 1: --help
Parameter 2: me
$ python arguments-output.py --option "long string"
Parameter 1: --option
Parameter 2: long string
Pamiętaj, że celem pokazania cytowanego przykładu łańcucha jest to, że parametry są zwykle oddzielone spacją, chyba że otoczone są cytatami.
Flagi zjazdu (absl
)
Biblioteka Flags firmy Abseil ma na celu wprowadzenie argumentów wiersza poleceń do produkcji z rozproszonymi argumentami wiersza poleceń. Gdy moduł używa flag wiersza poleceń i jest importowany do innego modułu – innego modułu importuje również flagii może je przetwarzać, przekazując je do zaimportowanego modułu.
Dzięki temu złożone argumenty wiersza poleceń współdzielone między modułami są łatwiejsze i mniej szczegółowe.
Dodatkowo biblioteka umożliwia zdefiniowanie wartości domyślnych, opisów i typów danych argumentów, więc dodatkowe kontrole i konwersje nie są konieczne.
from absl import flags
import sys
flags.DEFINE_string('name', 'User', 'The name of the user.')
FLAGS = flags.FLAGS
FLAGS(sys.argv)
print(f"Hello {FLAGS.name}!")
Obsługiwane typy danych to:
DEFINE_integer()
DEFINE_string()
DEFINE_bool()
DEFINE_enum()
DEFINE_list()
DEFINE_float()
Równie dobrze jak DEFINE_multi_integer()
, DEFINE_multi_string()
i DEFINE_multi_enum()
dla wprowadzania wieloargumentowego. Dodatkowo bieganie --help
, --helpfull
itp. wydrukuj istniejące flagi i ich opisy w różnych formatach.
Zapoznaj się z naszym praktycznym, praktycznym przewodnikiem dotyczącym nauki Git, zawierającym najlepsze praktyki, standardy przyjęte w branży i dołączoną ściągawkę. Zatrzymaj polecenia Google Git, a właściwie uczyć się to!
Biblioteka umożliwia również definiowanie walidacji – zarówno pod względem zakresu, jak np upper_bound
or lower_bound
jest to dopuszczalne i uruchamianie dowolnych metod w celu sprawdzenia wartości:
def validate_name(value):
return len(value) > 15
flags.register_validator('name',
validate_name,
message='Name is over 15 characters long.',
flag_values=FLAGS)
Zebranie ich w konkretny przykład:
from absl import flags
import sys
flags.DEFINE_string('name', 'User', 'The name of the user.')
flags.DEFINE_integer('tasks', 0, 'The number of tasks a user has.', lower_bound=0)
FLAGS = flags.FLAGS
FLAGS(sys.argv)
print(f"{FLAGS.name} has {FLAGS.tasks} tasks to work on.")
$ python flags.py --name=John --tasks=5
John has 5 tasks to work on.
$ python flags.py --name=John --tasks=-1
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_flag.py", line 180, in _parse
return self.parser.parse(argument)
File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/absl/flags/_argument_parser.py", line 168, in parse
raise ValueError('%s is not %s' % (val, self.syntactic_help))
ValueError: -1 is not a non-negative integer
...
Moduł argparse
Połączenia moduł argparse jest dostępny od Pythona 3.2, a ulepszenie optparse
moduł, który istnieje do Pythona 2.7. Dokumentacja Pythona zawiera opis interfejsu API i samouczek, który szczegółowo omawia wszystkie metody.
Moduł oferuje interfejs wiersza poleceń ze standardowym wyjściem, podczas gdy dwa poprzednie rozwiązania pozostawiają większość pracy w twoich rękach. argparse
pozwala na weryfikację argumentów stałych i opcjonalnych, ze sprawdzaniem nazw w stylu krótkim lub długim. Jako domyślny opcjonalny argument zawiera -h
, wraz z jego długą wersją --help
. Temu argumentowi towarzyszy domyślny komunikat pomocy opisujący akceptowane argumenty.
Poniższy kod przedstawia inicjalizację parsera, a poniższe dane wyjściowe pokazują podstawowe wywołanie, po którym następuje komunikat pomocy. W przeciwieństwie do wywołań Pythona, których użyliśmy w poprzednich przykładach, pamiętaj o użyciu Pythona 3 w tych przykładach:
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
$ python3 arguments-argparse-basic.py
$ python3 arguments-argparse-basic.py -h
usage: arguments-argparse-basic.py [-h]
optional arguments:
-h, --help show this help message and exit
$ python3 arguments-argparse-basic.py --verbose
usage: arguments-argparse-basic.py [-h]
arguments-argparse-basic.py: error: unrecognized arguments: --verbose
W następnym kroku dodamy niestandardowy opis do komunikatu pomocy dla naszych użytkowników. Zainicjowanie parsera w ten sposób pozwala na dodatkowy tekst. Poniższy kod przechowuje opis w text
zmienna, która jest jawnie przypisana do argparse
klasa jako description
parametr. Wywołując ten kod poniżej, możesz zobaczyć, jak wygląda wynik:
import argparse
text = 'This is a test program. It demonstrates how to use the argparse module with a program description.'
parser = argparse.ArgumentParser(description=text)
parser.parse_args()
$ python3 arguments-argparse-description.py --help
usage: arguments-argparse-description.py [-h]
This is a test program. It demonstrates how to use the argparse module with a
program description.
optional arguments:
-h, --help show this help message and exit
Jako ostatni krok dodamy opcjonalny argument o nazwie -V
, który ma odpowiedni długi argument o nazwie --version
. W tym celu używamy metody add_argument()
którą wywołujemy z trzema parametrami (wyświetlanymi dla --version
, tylko):
- Nazwa parametru:
--version
- Tekst pomocy dla parametru:
help="show program version"
- Akcja (bez dodatkowej wartości):
action="store_true"
Kod źródłowy tego jest wyświetlany poniżej. Wczytanie argumentów do zmiennej o nazwie args
odbywa się za pośrednictwem parse_args()
metoda z parser
obiekt. Pamiętaj, że przesyłasz zarówno krótką, jak i długą wersję w jednym wezwaniu. Na koniec sprawdzasz, czy atrybuty args.V
or args.version
są ustawione i wyświetlają komunikat o wersji:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-V", "--version", help="show program version", action="store_true")
args = parser.parse_args()
if args.version:
print("This is myprogram version 0.1")
$ python3 arguments-argparse-optional.py -V
This is myprogram version 0.1
$ python3 arguments-argparse-optional.py --version
This is myprogram version 0.1
Połączenia --version
argument nie wymaga podania wartości w wierszu poleceń. Dlatego ustawiliśmy argument akcji na "store_true"
. W innych przypadkach możesz potrzebować dodatkowej przypisanej wartości, na przykład jeśli określisz określoną objętość, wysokość lub szerokość. Pokazano to w następnym przykładzie. Domyślnie należy pamiętać, że wszystkie argumenty są interpretowane jako łańcuchy znaków:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--width", "-w", help="set output width")
args = parser.parse_args()
if args.width:
print("Set output width to %s" % args.width)
Tutaj pokazujemy, co się dzieje, gdy przesyłane są różne wartości argumentów. Obejmuje to zarówno wersję krótką, jak i długą, a także komunikat pomocy:
$ python3 arguments-argparse-optional2.py -w 10
Set output width to 10
$ python3 arguments-argparse-optional2.py --width 10
Set output width to 10
$ python3 arguments-argparse-optional2.py -h
usage: arguments-argparse-optional2.py [-h] [--width WIDTH]
optional arguments:
-h, --help show this help message and exit
--width WIDTH, -w WIDTH
set output width
Moduł getopt
Jak już pewnie zauważyliście, tzw sys
moduł dzieli ciąg wiersza poleceń tylko na pojedyncze aspekty. Pyton moduł getopt idzie nieco dalej i rozszerza separację ciągu wejściowego o sprawdzanie poprawności parametrów. Na podstawie getopt
Funkcja C, umożliwia zarówno krótkie, jak i długie opcje, w tym przypisanie wartości.
W praktyce wymaga to tzw sys
moduł do poprawnego przetwarzania danych wejściowych. Aby to zrobić, oba sys
moduł i getopt
moduł należy wcześniej załadować. Następnie z listy parametrów wejściowych usuwamy pierwszy element listy (patrz poniższy kod), a pozostałą listę argumentów wiersza poleceń przechowujemy w zmiennej o nazwie argument_list
:
import getopt, sys
full_cmd_arguments = sys.argv
argument_list = full_cmd_arguments[1:]
print argument_list
Argumenty w argument_list
można teraz analizować za pomocą getopts()
metoda. Ale zanim to zrobimy, musimy powiedzieć getopts()
o tym, które parametry są prawidłowe. Są one zdefiniowane w następujący sposób:
short_options = "ho:v"
long_options = ["help", "output=", "verbose"]
Oznacza to, że uważamy te argumenty za ważne, wraz z dodatkowymi informacjami:
------------------------------------------
long argument short argument with value
------------------------------------------
--help -h no
--output -o yes
--verbose -v no
------------------------------------------
Być może zauważyłeś, że o
krótka opcja została poprzedzona dwukropkiem, :
. To mówi getopt
że tej opcji należy przypisać wartość.
To pozwala nam teraz przetworzyć listę argumentów. The getopt()
Metoda wymaga skonfigurowania trzech parametrów – listy rzeczywistych argumentów z argv
, a także prawidłowe opcje short i long (pokazane w poprzednim fragmencie kodu).
Samo wywołanie metody jest przechowywane w instrukcji try-catch, aby pokryć błędy podczas oceny. Wyjątek jest zgłaszany, jeśli zostanie wykryty argument, który nie jest częścią listy, jak zdefiniowano wcześniej. Skrypt Pythona wyświetli komunikat o błędzie na ekranie i zakończy działanie z kodem błędu 2:
try:
arguments, values = getopt.getopt(argument_list, short_options, long_options)
except getopt.error as err:
print (str(err))
sys.exit(2)
Na koniec argumenty z odpowiednimi wartościami są przechowywane w dwóch nazwanych zmiennych arguments
i values
. Teraz możesz łatwo ocenić te zmienne w swoim kodzie. Możemy użyć A for
-loop do iteracji po liście rozpoznanych argumentów, jeden wpis po drugim.
for current_argument, current_value in arguments:
if current_argument in ("-v", "--verbose"):
print ("Enabling verbose mode")
elif current_argument in ("-h", "--help"):
print ("Displaying help")
elif current_argument in ("-o", "--output"):
print (("Enabling special output mode (%s)") % (current_value))
Poniżej możesz zobaczyć wynik wykonania tego kodu. Pokażemy, jak program reaguje na poprawne i nieprawidłowe argumenty programu:
$ python arguments-getopt.py -h
Displaying help
$ python arguments-getopt.py --help
Displaying help
$ python arguments-getopt.py --output=green --help -v
Enabling special output mode (green)
Displaying help
Enabling verbose mode
$ python arguments-getopt.py -verbose
option -e not recognized
Ostatnie wywołanie naszego programu może początkowo wydawać się nieco mylące. Aby to zrozumieć, trzeba wiedzieć, że opcji skrótowych (czasami nazywanych też flagami) można używać razem z pojedynczą kreską. Dzięki temu narzędzie łatwiej akceptuje wiele opcji. Na przykład dzwoniąc python arguments-getopt.py -vh
jest tym samym, co dzwonienie python arguments-getopt.py -v -h
. Tak więc w ostatnim wezwaniu powyżej, getopt
moduł myślał, że użytkownik próbuje przejść -e
jako opcja, która jest nieprawidłowa.
Wnioski
W tym artykule pokazaliśmy wiele różnych metod pobierania argumentów wiersza poleceń w Pythonie, w tym using sys
, getopt
, argparse
. Moduły te różnią się funkcjonalnością, niektóre zapewniają znacznie więcej niż inne. sys
jest w pełni elastyczny, podczas gdy oba getopt
i argparse
wymagają pewnej struktury. W przeciwieństwie do tego, obejmują one większość złożonych prac sys
pozostawia do ciebie. Po zapoznaniu się z podanymi przykładami powinieneś być w stanie określić, który moduł najlepiej pasuje do Twojego projektu.
W tym artykule nie rozmawialiśmy o innych rozwiązaniach, takich jak docopts
moduł, właśnie o tym wspomnieliśmy. Ten moduł opiera się na zupełnie innym podejściu i zostanie szczegółowo wyjaśniony w jednym z następnych artykułów.