Како рашчланити аргументе командне линије у Питхон-у

Želite li da pokrenete Python skripte koristeći argumente komandne linije? U ovom vodiču naučićete kako da parsirate argumente komandne linije uz pomoć modula `sys`, `getopt` i `argparse` u Python-u.

U Python-u, kada želite da pročitate unos od korisnika, koristićete funkciju `input()`. Međutim, za neke aplikacije, možda će biti neophodno da prosledite određene argumente prilikom pokretanja skripte putem komandne linije.

Ovaj vodič će vam pokazati kako da pokrenete Python skriptu sa opcijama i argumentima iz komandne linije. Zatim ćemo koristiti Python-ove ugrađene module za parsiranje tih opcija i argumenata.

Započnimo!

Razumevanje `sys.argv` u Python-u

Ako ste programirali u C-u, znate da je jedan od osnovnih načina za prosleđivanje argumenata programu putem komandne linije. Da biste to postigli, možete da struktuirate `main` funkciju na sledeći način:

#include<stdio.h>

int main(int argc, char **argv){
    //argc: broj argumenata
    //argv: vektor argumenata
    
    //obradite argumente
    return 0;
}

Ovde, `argc` predstavlja broj argumenata, dok `argv` predstavlja vektor argumenata.

Pokretanje Python skripti sa argumentima komandne linije

U Python-u, skriptu možete pokrenuti preko komandne linije koristeći `python3 filename.py`. Prilikom toga, možete uneti i proizvoljan broj argumenata:

$ python3 filename.py arg1 arg2 ... argn

Modul `sys` pruža jednostavan pristup i obradu ovih argumenata komandne linije. `sys.argv` je lista svih argumenata koje prosleđujemo prilikom pokretanja Python skripte.

Evo primera gde pokrećemo `main.py` sa argumentima komandne linije:

$ python3 main.py hello world python script

Kroz vektor argumenata možemo proći koristeći jednostavnu `for` petlju i funkciju `enumerate`:

# main.py

import sys

for idx, arg in enumerate(sys.argv):
    print(f"arg{idx}: {arg}")
# Izlaz
arg0:main.py
arg1:hello
arg2:world
arg3:python
arg4:script

Vidimo da je prvi argument (na indeksu 0) ime Python datoteke, dok naredni argumenti počinju od indeksa 1.

Ovo je osnovni funkcionalni program koji prihvata i obrađuje argumente komandne linije. Međutim, postoje određeni problemi:

  • Kako korisnici programa znaju koje argumente treba da unesu?
  • I šta ovi argumenti predstavljaju?

Ovo nije sasvim jasno. Da biste ovo rešili, možete koristiti module `getopt` ili `argparse`. To ćemo istražiti u narednim odeljcima.✅

Parsiranje argumenata komandne linije pomoću Python-ovog `getopt`-a

Naučimo sada kako da parsiramo argumente komandne linije koristeći ugrađeni modul `getopt`.

Nakon uvoza funkcije `getopt` iz modula `getopt`, definišemo argumente za parsiranje, kratke opcije i duge opcije za pokretanje skripte. Treba nam parsiranje argumenata, počevši od indeksa 1 u `sys.argv`, stoga se parsira `sys.argv[1:]`.

U našem primeru, biće nam potrebni argumenti za poruku i naziv datoteke. Koristićemo `m` i `f` kao kratke opcije, a `message` i `file` kao duge opcije.

Kako da označimo da određena opcija zahteva argument?

  • U kratkim opcijama, argument opcije označavamo dodavanjem dvotačke (:) iza kratkog naziva opcije.
  • Slično, kod dugih opcija, argument označavamo dodavanjem znaka = iza duge opcije. Na ovaj način možemo da uhvatimo opcije i njihove argumente.

Kada dodamo te oznake, naš kod u `main.py` će izgledati ovako:

# main.py

import sys
from getopt import getopt

opts, args = getopt(sys.argv[1:],'m:f:',['message=","file="])

print(opts)
print(args)

Ovde promenljiva `opts` sadrži opcije i argumente kao listu torki. Svi pozicioni argumenti koje prosledimo biće sačuvani u promenljivoj `args`.

Možemo uneti poruku i naziv datoteke prilikom pokretanja skripte, koristeći kratke ili duge opcije.

Pokrećemo `main.py` pomoću dugih opcija:

$ python3 main.py --message hello --file somefile.txt

Opcije i argumenti su sada torke u promenljivoj `opts`. Pošto nismo prosledili pozicione argumente, `args` je prazna lista.

# Izlaz
[('--message', 'hello'), ('--file', 'somefile.txt')]
[]

Isto možemo postići koristeći i kratke opcije:

$ python3 main.py -m hello -f somefile.txt
# Izlaz
[('-m', 'hello'), ('-f', 'somefile.txt')]
[]

⚠ Kratku opciju `-m` u ovom primeru ne treba mešati sa zastavicom komandne linije `-m`, koja se koristi za pokretanje modula kao glavnog modula prilikom pokretanja Python skripte.

Na primer, koristili biste `python3 -m unittest main.py` za pokretanje `unittest` kao glavnog modula prilikom pokretanja `main.py`.

Rekli smo da će svi ostali pozicioni argumenti koje prosledimo biti sačuvani u promenljivoj `args`. Evo primera:

$ python3 main.py -m hello -f somefile.txt another_argument

Lista `args` sada sadrži pozicioni argument `another_argument`.

# Izlaz
[('-m', 'hello'), ('-f', 'somefile.txt')]
['another_argument']

Ovde je `opts` lista torki, kroz koju možemo da prođemo, raspakujemo torke i izvučemo argumente koji odgovaraju određenim opcijama.

Šta da radimo sa imenom datoteke i porukom nakon obrade argumenata? Otvorićemo datoteku u režimu pisanja i upisati poruku, pretvorenu u velika slova, u datoteku.

# main.py
import sys
from getopt import getopt

opts, args = getopt(sys.argv[1:],'m:f:',['message=","file="])

print(opts)
print(args)

for option, argument in opts:
    if option == "-m":
        message = argument
    if option == '-f':
        file = argument

with open(file,'w') as f:
    f.write(message.upper())

Pokrenimo `main.py` sa kratkim opcijama i argumentima komandne linije:

$ python main.py -m hello -f thisfile.txt
[('-m', 'hello'), ('-f', 'thisfile.txt')]
[]

Nakon pokretanja `main.py`, u radnom direktorijumu možemo videti `thisfile.txt`. Sadrži string `hello` pretvoren u velika slova (`HELLO`).

$ ls
main.py  thisfile.txt
$ cat thisfile.txt
HELLO

Kako parsirati argumente komandne linije pomoću `argparse`-a

Modul `argparse`, koji je takođe deo Python standardne biblioteke, pruža funkcionalnost za parsiranje argumenata komandne linije i kreiranje interfejsa komandne linije.

Da bismo parsirali argumente komandne linije, importujemo klasu `ArgumentParser` iz modula `argparse`. Ovde instanciramo `arg_parser`, objekat `ArgumentParser`:

from argparse import ArgumentParser

arg_parser = ArgumentParser()

Zatim ćemo dodati dva argumenta komandne linije:

  • `message`: string poruke i
  • `file`: naziv datoteke sa kojom želimo da radimo.

Pozivamo metod `add_argument()` na `arg_parser` da bismo dodali oba ova argumenta. U pozivu metode `add_argument()`, možemo postaviti pomoć za string (opis argumenta).

arg_parser.add_argument('message',help='string poruke')
arg_parser.add_argument('file',help='ime datoteke')

Do sada smo instancirali `arg_parser` i dodali argumente komandne linije. Kada se program pokrene iz komandne linije, metod `parse_args()` na `arg_parser` će vratiti vrednosti argumenata.

Ovde hvata prostor imena argumenata u promenljivoj `args`. Stoga, možemo koristiti `args.argument_name` da dobijemo vrednosti argumenata.

Nakon što dobijemo vrednosti argumenata, u datoteku upisujemo string poruke sa zamenjenim malim i velikim slovima (koristeći string metod `swapcase()`).

args = arg_parser.parse_args()

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

Sve zajedno, naša `main.py` datoteka izgleda ovako:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('message',help='string poruke')
arg_parser.add_argument('file',help='ime datoteke')

args = arg_parser.parse_args()
print(args)

message = args.message
file = args.file

with open(file,'w') as f:
     f.write(message.swapcase())

Razumevanje upotrebe argumenata komandne linije

Da biste videli uputstvo o argumentima prilikom pokretanja `main.py`, koristite opciju `–help`, kao što je prikazano:

$ python3 main.py --help
usage: main.py [-h] message file

positional arguments:
  message     string poruke
  file        ime datoteke

optional arguments:
  -h, --help  prikazuje ovu pomoćnu poruku i izlazi

Ne postoje opcioni argumenti, a `message` i `file` su oba obavezni pozicioni argumenti. Alternativno, možete koristiti i kratku opciju `-h`:

$ python3 main.py -h
usage: main.py [-h] message file

positional arguments:
  message     string poruke
  file        ime datoteke

optional arguments:
  -h, --help  prikazuje ovu pomoćnu poruku i izlazi

Kao što se vidi, oba argumenta su podrazumevano pozicioni. Dakle, ako ne prosledite jedan ili više ovih argumenata, doći će do greške.

Ovde smo prosledili pozicioni argument `Hello` za string poruke, ali nismo dali nikakvu vrednost za argument datoteke.

I dobićemo grešku koja nam govori da je argument datoteke obavezan.

$ python3 main.py Hello
usage: main.py [-h] message file
main.py: error: sledeći argumenti su neophodni: file

Kada pokrenemo `main.py` sa oba poziciona argumenta, vidimo da prostor imena `args` sadrži vrednosti argumenata.

$ python3 main.py Hello file1.txt
# Izlaz
Namespace(file="file1.txt", message="Hello")

Sada, ako ispitamo sadržaj trenutnog radnog direktorijuma, vidimo da je skripta kreirala datoteku `file1.txt`:

$ ls
file1.txt  main.py

Originalni string poruke je `Hello`, a nakon zamene slova, string u datoteci `file1.txt` je `hELLO`.

$ cat file1.txt
hELLO

Kako da argumente komandne linije učinimo opcionim

Da biste argumente komandne linije učinili opcionim, dodajte prefiks `–` imenu argumenta.

Izmenimo `main.py` da bismo argumente poruke i datoteke učinili opcionim.

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='string poruke')
arg_parser.add_argument('--file',help='ime datoteke')

Pošto su argumenti komandne linije sada opcioni, možemo postaviti podrazumevane vrednosti za njih.

if args.message and args.file:
    message = args.message
    file = args.file
else:
    message="Python3"
    file="myfile.txt"

U ovom trenutku, datoteka `main.py` sadrži sledeći kod:

# main.py

from argparse import ArgumentParser

arg_parser = ArgumentParser()
arg_parser.add_argument('--message',help='string poruke')
arg_parser.add_argument('--file',help='ime datoteke')

args = arg_parser.parse_args()
print(args)

if args.message and args.file:
    message = args.message
    file = args.file
else:
    message="Python3"
    file="myfile.txt"

with open(file,'w') as f:
     f.write(message.swapcase())

Ako proverimo uputstvo, videćemo da su i `message` i `file` sada opcioni argumenti. To znači da sada možemo pokrenuti `main.py` bez oba ova argumenta.

$ python3 main.py --help
usage: main.py [-h] [--message MESSAGE] [--file FILE]

optional arguments:
  -h, --help         prikazuje ovu pomoćnu poruku i izlazi
  --message MESSAGE  string poruke
  --file FILE        ime datoteke
$ python3 main.py

U prostoru imena argumenata, i datoteka i poruka su `None`.

# Izlaz
Namespace(file=None, message=None)

Vidimo da se koriste podrazumevano ime datoteke i poruka, `myfile.txt` i `Python3`. Datoteka `myfile.txt` sada postoji u radnom direktorijumu:

$ ls
file1.txt  main.py  myfile.txt

I sadrži string `Python3` sa zamenjenim malim i velikim slovima:

$ cat myfile.txt
pYTHON3

Takođe, možemo koristiti argumente `–message` i `–file` da bi komanda bila čitljivija.

$ python3 main.py --message Coding --file file2.txt
# Izlaz
Namespace(file="file2.txt", message="Coding")

Vidimo `file2.txt` u radnom direktorijumu:

$ ls
file1.txt  file2.txt  main.py  myfile.txt

I sadrži string `coding`, kao što se i očekivalo.

$ cat file2.txt
cODING

Zaključak

Evo rezimea onoga što smo naučili u ovom vodiču:

  • Slično programskom jeziku C, u Python-u možete pristupiti argumentima komandne linije prolazeći kroz vektor argumenata `sys.argv`. `sys.argv[0]` je naziv Python skripte. Stoga nas zanima parsiranje argumenata `sys.argv[1:]`.
  • Međutim, radi bolje čitljivosti i dodavanja opcija, možete koristiti module `getopt` i `argparse`.
  • Modul `getopt` možete koristiti za parsiranje liste argumenata komandne linije počevši od indeksa 1 do kraja liste. Možete definisati i kratke i duge opcije.
  • Kada opcija prihvata argument, možete da odredite dvotačku (:) i znak `=` posle kratke i duge opcije, respektivno.
  • Pomoću Python-ovog modula `argparse` možete instancirati objekat `ArgumentParser` i koristiti metod `add_argument()` da dodate željeni pozicioni argument. Koristite `–` ispred imena argumenta da biste ga učinili opcionim.
  • Da biste preuzeli vrednosti argumenata komandne linije, pozovite metod `parse_args()` na objektu `ArgumentParser`.

Zatim naučite kako da izvršite bezbedno heširanje u Python-u.