Bash dla Hobbystów. Pętle

Jeśli chodzi o pętle w przypadku bash, to jego twórcy uraczyli nas aż trzema rozwiązaniami w tym zakresie. Jednakże trzeba uczciwie powiedzieć, że de facto dwa spośród nich są do siebie bliźniaczo podobne i nie do końca jest dla mnie jasne po co była taka rozrzutność w tym zakresie, skoro w praktyce wystarczyłaby wyłącznie pętla for.

Pętla “while” oraz “until”

Tym niemniej wpis zaczniemy od dwóch pozostałych, czyli while oraz until. Na najwyższym poziomie abstrakcji ich struktura wygląda następująco:

while/until [sprawdzany warunek ]

do

      instrukcje do wykonania

done

Oczywiście pomiędzy kwadratowe wiersze wstawiamy jakiś rodzaj testu, o którym była mowa przy okazji wpisu o instrukcjach warunkowych.  W przypadku pętli while mamy do czynienia z sytuacji, w której dopóki w wyniku tego sprawdzianu będzie zwracana wartość true, dopóty instrukcje znajdujące się pomiędzy słowami kluczowymi do oraz done będą wykonywane raz za razem.

#!/bin/bash

licznik=1

while [ $licznik -le 10 ]

do

echo $licznik

((licznik++))

done

W efekcie wykonania tego kawałka kodu w terminalu powinno się wyświetlić lista kolejnych cyfr od 1 do 10. Rzecz jasna dla osób z jakimkolwiek doświadczeniem w kodowaniu było to banalne do przewidzenia, ponieważ przykład ten powinien być zrozumiały i czytelny sam przez się. Tym niemniej gwoli dydaktycznej staranności rozpiszemy, co tam się faktycznie zadziałało (krok po kroku).

  1. Na początku inicjalizujemy zmienną “licznik” z wartością 1.
  2. W kolejnej linii mam początek pętrli, gdzie przeprowadzany jest test, weryfikujący czy wartość podstawionej zmiennej “licznik”  jest mniejszy lub równy 10 (dla przypomnienia: w przypadku testów bash “-le” właśnie to oznacza, czyli mniejszy lub równy).
  3. Jeśli warunek jest spełniony wówczas wykonywana jest sekcja poleceń, która tutaj sprowadza się do wypisania na standardowym wyjściu (czytaj w tym wypadku: “w terminalu”) wartości zmiennej “licznik”, a następnie dochodzi do zwiększenia wartości tej zmiennej o jeden.
  4. W kolejnym kroku wracamy na początek naszej pętli i ponownie testujemy wartość zmiennej “licznik”, która tym razem jest o jeden większa. Jeśli warunek jest nadal prawdziwy, sekwencja zdarzeń się powtarza.
  5. Będzie się tak działo do momentu, aż wartość naszej zmiennej przekroczy graniczny poziom (tutaj równy 10).

W przypadku pętli until jedyna różnica polega na tym, że pętla będzie tak długo się wykonywać dopóki warunek – odwrotnie niż dla while – nie zostanie spełniony, czyli “oczekiwaną” wartością jest tutaj false zamiast true. W związku z czym należy po prostu sformułować negację (przeciwieństwo) poprzedniego warunku, by otrzymać ten sam efekt jak wyżej.

#!/bin/bash

licznik=1

until [ $licznik -gt 10 ]

do

echo $licznik

((licznik++))

done

Gwoli przypomnienia: “-gt” oznacza “jest większy niż”.  

Pętla “for”

Pętla for wydaje się akurat tą strukturą, która prawdopodobnie znacznie częściej stosowana jest w przypadku skryptów bash niż dwie wcześniej omówione. W zasadzie duża część zadań, które chcemy zautomatyzować za pomocą skryptów, sprowadza się do iteracji jakiej listy wartości, które są zwracane w wyniku działania innego polecenia lub po prostu zostały pobrane z innego źródła/pliku. Co więcej: przy pomocy pętli for da się wykonać w większości przypadków w dość prosty sposób dokładnie to samo, co za pomoć chociażby while. W drugę stronę nie jest to zaś takie oczywiste.

W najogólniejsze postaci pętla for ma następującą postać:

for <nazwa zmiennej> in <lista wartości>

do 

    instrukcje do wykonania $<nazwa zmiennej>

done

By tej abstrakcyjnej formie nadać nieco więcej konkretności posłużymy się następującym przykładem:

#!/bin/bash

for imie in Kasia Zosia Marysia

do

echo $imie

done

W wyniku działania tej pętli w terminalu zostanie zaprezentowany wynik w postaci trzech kolejnych wierszy, w których pojawio się imiona “Kasia”, “Zosia” oraz “Marysia” (właśnie w takiej kolejności).

Inną często spotykaną w skryptach postacią pętli for jest konstrukcja, którą określa się dość powszechnie “w stylu C”. Nie za bardzo wiem skąd to określenie (węszę tu jakieś naleciałości historyczne), ale na podobne rozwiązania natknąć się można w przypadku większości (o ile nie wszystkich) popularnych języków kodowania.

Niżej przykład pętli for w stylu C, który wykonuje dokładnie to samo, co wcześniej zostało zaprezentowane dla pętli while oraz until.

#!/bin/usr/env bash

n=10

for (( i=1 ; i<=$n ; i++ ))

do

    echo $i

done

Na koniec prezentacji pętli for został do omówienia dość często – nie wiedzieć czemu – pomijany sposób używania pętli for powiedzmy “w stylu range”. Pozostańmy nadal przy wałkowanym na różne sposoby ćwiczeniu polegającym na wyświetleniu po kolei liczb od 1 do 10 (każdej w osobnym wierszu). Całość wówczas wyglądałaby tak:

#!/bin/bash

for n in {1..10}

do

    echo $n

done

W nawiasach klamrowych wskazujemy liczbę początkową oraz końcową naszego zakresu, które to rozdzielamy dwoma kropkami (bardzo istotne by był to właśnie dwie kropki, a nie mniej czy więcej). Tym sposobem generowany jest ciąg kolejnych liczb z podanego zakresu ze skokiem o jeden. Gdybyśmy jednak chcieli zwiększyć ten skok wystarczy dorzucić na końcu odpowiednią wartość, tak jak widać to niżej.

#!/bin/usr/env bash

for n in {1..10..2}

do

    echo $n

done

W zasadzie to byłoby na tyle, jeśli chodzi o pętle w bash. Jak można było się przekonać nie ma tutaj niczego odkrywczego czy zaskakującego – od siebie dodam “na szczęście”. Tym sposobem właściwie można uznać ten cykl za zamknięty, choć do omówienia zostały jeszcze funkcje, czego rzecz jasna nie omieszkam zrobić w kolejnym wpisie. Tym niemniej uzbrojony w znajomość tworzenie funkcji, instrukcji warunkowych oraz pętli jesteśmy w stanie zautomatyzować niemal dowolną czynność, którą zwyczajowo wykonywaliśmy klepiąc polecenie po poleceniu.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *