Kontynuujemy temat Python w systemie Linux. W tym materiale poznamy czym są funkcje oraz w jaki sposób z nich korzystać. Oczywiście wymagana jest wiedza z dwóch wcześniejszych artykułów. Dlatego jeżeli nie zapoznałeś się ze wcześniejszymi materiałami zapraszam do części 1 oraz części 2. Przejdźmy do dalszych zagadnień związanych z programowaniem.

 

Zapis na newsletter!

Zanim jednak rozwinę temat dalej to jedna informacja na początek. Prowadzę regularny, cotygodniowy newsletter z poradami związanymi z Zabbixem, monitoringiem oraz dobrymi praktykami w IT. Jeżeli nie chcesz przegapić kolejnych części oraz zaproszeń na nasze darmowe szkolenia to zapraszam do zapisu. Wystarczy pobrać mój poradnik. Monitoring IT – Dobre Praktyki. Wystarczy wejść klikając na obrazek:

__________________________________________

 

Python w systemie Linux – modyfikacja poprzedniego kodu

Analizując poprzedni kod można dojść do wniosku, że podawanie nazwy systemu nie jest dobrym rozwiązaniem. Zamiast tego lepiej wpisać nazwę menadżera pakietów z jakiego się korzysta. W związku z tym wprowadźmy pewne zmiany do naszego skryptu:

system.add_argument("-m", "--menadzer-pakietow", dest="menadzer", help="podajemy nazwę menadżera pakietów z jakiego korzysta nasz system")

Zmieniamy opcje -s na -m w której podawać będziemy nazwę menadżera pakietów z jakiego korzysta nasza dystrybucja. Nic nowego, poza zmianą nazw i opisów się nie pojawiło. Teraz musimy zmienić sposób otrzymania tej informacji. Ale nim zajmiemy się przechwyceniem danych stwórzmy listę dostępnych menadżerów pakietów:

menadzer_pakietow = ['apt', 'dnf', 'yum']

W przykładzie stworzyliśmy co w języku Python nazywa się listą. Lista jest to zbiór elementów zapisanych pod jedną nazwą. Oznacza to, że nie nie tworzymy kilku zmiennych i przypisujemy do nich wartości, tylko grupujemy je w jeden element. Najczęściej takiemu grupowaniu poddajemy elementy które są pod względem funkcjonalnym zależne od siebie lub zbliżone. Inaczej mówiąc nie grupuje się losowych liczb i nazw w jeden element ponieważ takich list w żaden sposób się nie wykorzysta.

W naszym wypadku stworzyliśmy listę zawierającą nazwy menadżerów pakietów. Zerknij na poniższy przykład, zapisałem go pod nazwą listy.py:

#!/usr/bin/env python3

menadzer_pakietow = ['apt', 'dnf', 'yum']

print(menadzer_pakietow)

print(menadzer_pakietow[0])

print(menadzer_pakietow[1])

print(menadzer_pakietow[2]) 

Następnie uruchommy skrypt z powyższego przykładu:

python3 listy.py

['apt', 'dnf', 'yum']

apt

dnf

yum

W kodzie wypisaliśmy cztery instrukcje print. Po uruchomieniu pojawiły się cztery linie wyświetlające wartości. Pierwsza z nich wyświetla całą listę z wartościami w niej zawartymi. Natomiast w pozostałych korzystając z wartości liczbowych wpisanych w kwadratowy nawias otrzymujemy pojedyncze wartości. W ten sposób zgrupowaliśmy w jedną etykietę nazwy menadżerów pakietów, a w prezentowany sposób jesteśmy w stanie do nich uzyskać dostęp.

Jeżeli chodzi o numerowanie to pamiętaj, że w programowaniu wszystko zaczyna się od 0. Czyli jeżeli chcesz wypisać w liście 10 pierwszych wartości to zaczynasz od 0 a kończysz na 9. Drugą istotną sprawą jest to, żeby nigdy nazywając cokolwiek w programowaniu nie używać polskich znaków.

W innych językach to co my nazywamy listą, najczęściej jest określane jako tablica.

Wiesz już w jaki sposób wypisać wartości znajdujące się w tablicy. Natomiast nim przejdę dalej wróćmy do naszego pierwotnego kodu. Usuńmy instrukcje if elif i else oraz instrukcję subprocess i zapiszmy kod w następujący sposób:

if opcje.menadzer in menadzer_pakietow:

      subprocess.call("sudo " + opcje.menadzer + " update && sudo " + opcje.menadzer + " dist-upgrade -y", shell=True)

else:

      print('Wprowadzony menażer pakietów jest nieobsługiwany przez skrypt')

Instrukcja warunkowa if posiada ciekawą możliwość sprawdzenia czy wartość znajduje się na liście.

Powyższą część kodu możemy przetłumaczyć na język polski w następujący sposób:

Czy wartość opcje.menadzer znajduje się na liście menadzer_pakietow? Jeżeli tak to uruchom funkcję subprocess i dokonaj aktualizacji z przekazanymi danymi. Jeżeli nie to wyświetl informację, że wprowadzony menażer pakietów jest nieobsługiwany przez nasz skrypt.

Cały kod prezentuje się w następujący sposób:

#!/usr/bin/env python3

import subprocess

import argparse

system = argparse.ArgumentParser()

system.add_argument("-m", "--menadzer-pakietow", dest="menadzer", help="podajemy nazwę menadżera pakietów z jakiego korzysta nasz system")

opcje = system.parse_args()

menadzer_pakietow = ['apt', 'dnf', 'yum']

if opcje.menadzer in menadzer_pakietow:

      subprocess.call("sudo " + opcje.menadzer + " update && sudo " + opcje.menadzer + " dist-upgrade -y", shell=True)

else:

      print('Wprowadzony menażer pakietów jest nieobsługiwany przez skrypt')

Pamiętamy, że zmieniliśmy opcję do przekazywania argumentów, w której wypisujemy nazwę menadżera pakietów, z którego korzystamy. W związku z tym uruchamiamy skrypt w następujący sposób:

python3 cztery.py -m yum

Jeżeli chodzi o menadżer pakietów yum i dnf które są dostępne w dystrybucjach Red Hat i opartych o niego aktualizacja oraz instalacja wykonywana jest przy pomocy jednego polecenia. Jeżeli użyłeś skryptu z użyciem wymienionych menadżerów pakietów to otrzymałeś informację:

Nie ma takiego polecenia: dist-upgrade. Proszę użyć „/bin/dnf –help”

Może to być polecenie wtyczki programu DNF, proszę spróbować polecenia: „dnf install 'dnf-command(dist-upgrade)’”

Choć aktualizacja została wykonana to jednak, źle to wygląda dlatego musimy coś z tym zrobić.

Python w systemie Linux – zagnieżdżenie instrukcji warunkowych

W tej sytuacji, gdy skrypt napotka jeden z tych dwóch menażerów pakietów to wykonana zostania pierwsza część polecenia. Do tego zagnieździmy instrukcje warunkowe:

if opcje.menadzer in menadzer_pakietow:

      if opcje.menadzer == 'dnf' or 'yum':

            subprocess.call("sudo " + opcje.menadzer + " update -y", shell=True)

      else:

            subprocess.call("sudo " + opcje.menadzer + " update && sudo " + opcje.menadzer + " dist-upgrade -y", shell=True)

else:

      print('Wprowadzony menażer pakietów jest nieobsługiwany przez skrypt')

Po tym jak potwierdziliśmy, że wprowadzony przez nas menadżer pakietów jest dostępny zagnieżdżamy instrukcję warunkową pod potwierdzoną instrukcją. W tej zagnieżdżonej instrukcji sprawdzamy, czy menadżerem pakietów jest dnf lub yum. Zwróć uwagę, przy użyciu słowa or możesz sprawdzić warunek. Dlatego, jeżeli przekazany zostanie dnf lub yum wykona się część kodu odpowiedzialna za aktualizację. Natomiast w przypadku, gdy będzie to inny menadżer pakietów, to skorzysta z rozwiązania bardziej rozbudowanego. Nie ma sensu wprowadzać  dodatkowych warunków, ponieważ pierwsza instrukcja potwierdziła, że dany menadżer pakietów znajduje się na liście dostępnych.

Teraz jeżeli uruchomisz skrypt w systemie Red Hat lub opartym o niego nie otrzymasz już wskazanego błędu.

Funkcje języka Python w systemie Linux

Cały kod możemy pogrupować w tak zwane funkcje. Dzięki nim kod będzie czytelniejszy oraz zaistnieje możliwość jego powtórnego wykorzystania. To, co tutaj poznasz będzie wprowadzeniem do funkcji. Temat jest dość rozbudowany, a chcę wyjaśniać wszystko na przykładach. Dlatego do samych funkcji będziemy jeszcze wracać wielokrotnie.

Stworzony przez nas skrypt możemy podzielić na dwa oddzielne moduły. Pierwszy z nich to miejsce, w którym tworzymy opcje. Drugi to, gdy wykorzystujemy opcje by móc zaktualizować system. Z wspomnianych elementów stworzymy dwie oddzielne funkcje. W tym wypadku proponuję zapisać dokument jako nowy plik. W związku z tym, że jest to piąty skrypt w tej serii artykułów nazywam go piec.py. Tak jak poznałeś wcześniej tworzymy nagłówek:

#!/usr/bin/env python3

import subprocess

import argparse

Nic nowego nie dodałem, w związku z tym opis uważam za zbędny.

def opcjeWywolania():

      system = argparse.ArgumentParser()

      system.add_argument("-m", "--menadzer-pakietow", dest="menadzer", help="podajemy nazwę menadżera pakietów z jakiego korzysta nasz system")

      opcje = system.parse_args()

      if not opcje.menadzer:

            system.error('Nie określiłeś menadżera pakietów z jakiego korzystasz!')

      return opcje

Funkcje tworzymy przy użyciu etykiety def po czym podajemy nazwę po której wypisujemy nawias () i dwukropek :. Jest to nagłówek funkcji. To co występuje po nagłówku są to instrukcje które będą wykonywane wewnątrz funkcji, po jej wywołaniu. Pierwsze trzy linie kodu znajdujące się w funkcji są identyczne jak te które stworzyliśmy w poprzednim kodzie. Stąd też wiesz do czego służą. To w tym miejscu od teraz będziesz tworzył dodatkowe opcje dla swojego skryptu.

Następnie dodaliśmy instrukcję warunkową if w której skorzystaliśmy ze słowa kluczowego not. Dzięki temu w przypadku gdy nie określimy wartości opcji -m zostanie wywołana instrukcja znajdująca się w treści tej instrukcji warunkowej.

W pierwszej części artykułów o Python poznaliśmy instrukcję print.

Moglibyśmy z niej skorzystać, ale powstałby problem, bo program przeszedłby do następnej instrukcji lub funkcji. Dlatego skorzystaliśmy z opcji system.error dostępnej w bibliotece argparse dzięki której zostanie wyświetlona informacja wpisana pomiędzy nawiasami. A co ważniejsze program zakończy swoje działanie. Dlatego pozostałe funkcje nie zostaną wywołane.

Nie wiem czy to wyjaśnienie do Ciebie trafiło. Dlatego postanowiłem jeszcze chwilę temu poświęcić.  Jeżeli nie określimy wartości początkowej opcji -m to menadzer do którego ta wartość ma trafić nie ulegnie zmianom. Czyli będzie miała wpisaną wartość None ponieważ wszystkie zmienne posiadają początkową wartość None. Bez użytej instrukcji warunkowej if oraz instrukcji system.error ta wartość zostanie przekazana dalej. Oznaczać to będzie, że do naszego subprocessu gdzie wywołujemy polecenie aktualizacji zostanie przypisana wartość None. Natomiast my tego nie chcemy, ponieważ nie ma to sensu. Nie ma wprowadzonej wartości nie ma sensu sprawdzać dalej. Należy zakończyć działanie programu. Zakończyć nie uda nam się przy pomocy print dlatego korzystamy z wbudowanej możliwości system.error.

Na samym końcu zwracamy przy pomocy instrukcji return opcje jakie ustawiliśmy w funkcji.

Teraz poza funkcją przypisujemy zwracaną wartość do zmiennej:

opcje = opcjeWywolania()

Funkcje które zwracają wartość przy pomocy instrukcji return mogą, ale nie muszą być zapisane do zmiennej. Tak jak zrobiliśmy to w powyższym przykładzie. W ten sposób przy pomocy funkcji przekazaliśmy zmiennej argumenty wywołane przy uruchomieniu skryptu.

Pierwszą funkcję mamy za sobą. Zobaczmy teraz jak wygląda druga część kodu:

def systemMenagers(menadzer):

      menadzer_pakietow = ['apt', 'dnf', 'yum']

      if menadzer in menadzer_pakietow:

            if menadzer == 'dnf' or 'yum':

                  subprocess.call("sudo " + menadzer + " update -y", shell=True)

            else:

                  subprocess.call("sudo " + menadzer + " update && sudo " + opcje.menadzer + " dist-upgrade -y", shell=True)

      else:

             print('Wprowadzony menażer pakietów jest nieobsługiwany przez skrypt')

W wypadku tej części również tworzymy funkcje o nazwie systemMenagers. Jednak w tym wypadku wewnątrz nawiasu wprowadziłem argument menadzer. W poprzednim przypadku  zawartość nawiasu była pusta. Nie było potrzeby przekazywania jakiejkolwiek wartości. Tym razem do funkcji będziemy chcieli przekazać argument. Nazwa jaką tutaj wprowadzisz nie ma takiego znaczenia. Istotne jest żebyś korzystał z niej w swojej funkcji. Zerknij na powyższy kod i zobacz w jakich miejscach została użyta nazwa z nawiasu. Najlepiej porównaj to do kodu gdzie nie korzystaliśmy z funkcji.

Jeżeli chodzi o zawartość funkcji to nie różni się ona od tego co pisaliśmy bez jej użycia. Jedynie występują trochę głębsze wcięcia. W związku z tym teraz musimy przekazać tej funkcji wartość uzyskaną z poprzedniej. Czyli musimy podać jej wartość którą wpisaliśmy przy uruchomieniu skryptu:

systemMenagers(opcje.menadzer)

Teraz bardzo ważne. W taki sposób wywołujemy funkcję przekazując jej argument. Nie jest ona zapisana do żadnej zmiennej ponieważ jako wynik jej działania nie przekazuje nic. Nie ma instrukcji return więc nic nie zwraca. W funkcji przekazujemy zmienną opcje która uzyskała dostęp do wartości menadzer ( opcje.menadzer ) znajdującej się w funkcji opcjeWywolana. To w niej jest zapisana wartość którą przekazaliśmy podczas uruchomienia skryptu.

Teraz najlepiej jakbyś zerknął w kod i wzrokowo zastąpił w funkcji systemMenagers zmienną menadzer przekazaną wartością opcje.menadzer.

Tak to działa, dlatego nazwa jaką wprowadzisz podczas tworzenia funkcji nie ma znaczenia. Jednak dobrze jest ją określać w sposób jasny dla siebie i innych.

W tym momencie powinniśmy mieć skrypt prezentujący się w następujący sposób:

#!/usr/bin/env python3

import subprocess

import argparse

def opcjeWywolania():

      system = argparse.ArgumentParser()

            system.add_argument("-m", "--menadzer-pakietow", dest="menadzer", help="podajemy nazwę menadżera pakietów z jakiego korzysta nasz system")

      opcje = system.parse_args()

      if not opcje.menadzer:

             system.error('Nie określiłeś menadżera pakietów z jakiego korzystasz!')

      return opcje

def systemMenagers(menadzer):

      menadzer_pakietow = ['apt', 'dnf', 'yum']

      if menadzer in menadzer_pakietow:

            if menadzer == 'dnf' or 'yum':

                  subprocess.call("sudo " + menadzer + " update -y", shell=True)

            else:

                  subprocess.call("sudo " + menadzer + " update && sudo " + opcje.menadzer + " dist-upgrade -y", shell=True)

      else:

            print('Wprowadzony menażer pakietów jest nieobsługiwany przez skrypt')

opcje = opcjeWywolania()

systemMenagers(opcje.menadzer)

Jeżeli korzystasz z zintegrowanego środowiska programistycznego, to najprawdopodobniej masz możliwość zwijania części kodu. Jeżeli obok funkcji, które teraz stworzyliśmy znajduje się + lub inny znaczek umożliwiający zwijanie to także skorzystaj z niego. W ten sposób przygotowany i działający kod możesz ukryć ze swojego monitora. Choć prosta to jednak bardzo pożyteczna opcja.

Uruchom swój skrypt i sprawdź jak działa. Po napisaniu takiego zawsze warto sprawdzić w jaki sposób on działa. Wypróbować kilka opcji, popełnić kilka błędów i zobaczyć, co wtedy się stanie.

Chciałbym jeszcze Ci coś pokazać. Usuń z końca swojego skryptu dwie ostatnie linie:

opcje = opcjeWywolania()
systemMenagers(opcje.menadzer)

I wpisz:

systemMenagers(opcjeWywolania().menadzer)

W tym wypadku nie zapisaliśmy wartości funkcji opcjeWywolania() do zmiennej tylko od razu przekazaliśmy ją do drugiej funkcji. W związku z tym, że przekazujemy wartość znajdująca się wewnątrz tej funkcji nie możemy jej przekazać jako całość. Dlatego wprowadzamy zmienną jaką chcemy przekazać.

Czy jeden czy drugi, oba zapisy są poprawne. Który dla Ciebie będzie wygodniejszy zdecyduj sam. Na pewno zapis drugi będzie krótszy jednak wygodniej jest moim zdaniem korzystać z tego pierwszego rozwiązania.

Podsumowanie – Python w systemie Linux

Pisanie skryptów jest dość wymagające i wymaga również ogromnej praktyki. Teoria jest również wartościowa. Jednak większość z nas myślę, że woli mieć to wszystko wytłumaczone na przykładzie. To, co do tej pory przeczytałeś było wstępem by zrozumieć jak działa Python w systemie Linux. W następnych materiałach zajmiemy się także automatyzacją instalacji dockera w systemach Linux.

Chcesz więcej?

Oczywiście, jeżeli nie chcesz przegapić tego typu materiałów, to zapisz się na mój newsletter i przy okazji odbierz darmowe bonusy, np. e-booka ze zdjęcia poniżej! Prowadzę regularny, cotygodniowy newsletter z poradami związanymi z automatyzacją, monitoringiem oraz dobrymi praktykami w IT.

Zapisy TUTAJ

Zapisz się na Newsletter i odbierz za darmo e-book "Monitoring IT"!

X