Argumenty wiersza poleceń w Pythonie

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 -hlub -- 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] do sys.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, --helpfullitp. 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 getopti 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.

Referencje

Znak czasu:

Więcej z Nadużycie stosu