Na samym początku chciałbym zaznaczyć, że o ile będę starał się w miarę szczegółowo wyjaśniać poszczególne kwestie poruszane w dzisiejszym tekście, to zarówno dzisiaj jak i kolejnych odsłonach tego cyklu nie będę opowiadał o abecadle koderskim, na które składają się zmienne, pętle czy instrukcje warunkowe. Zakładamy po prostu, że czytelnik ma jakieś rozeznania w tym temacie, a w najgorszym wypadku będzie w stanie samodzielnie doczytać (tudzież “dozobaczyć”) czym są te konstrukcje programistyczne. Tym samy nie uświadczymy dzisiaj żadnych gawęd chociażby o pudełkach, które zawsze jak królik z kapelusza pojawiają się, gdy ktoś stara się wytłumaczyć laikom co to za dziwo ta “zmienna”. To powiedziawszy przejdźmy do rzeczy.
Komentarze
Ale wcześniej dwa słowa poświęcę komentarzom, tym bardziej, że jestem wielkim orędownikiem ich stosowania, zwłaszcza jeśli wiemy, że z naszego kodu mogą korzystać inne osoby.
Jeśli chodzi o basha, komentarze są poprzedzone znakiem #. Wszystko, co znajduje się w wierszu za tym symbolem, jest ignorowane przez powłokę. Nawet w przypadku wiersza shebang ( #!/bin/bash) mamy do czynienia – ze specjalnym wprawdzie – komentarzem, ponieważ jako taki nie jest on przez powłokę wykonywany. Ta ostatnia przetwarzając nasz skrypt odczytuje ten wiersz i stąd wie, którego interpretera poleceń użyć do wykonania zawartych tam instrukcji, ale wpływu na samo działanie programu nie ma to żadnego.
Jeśli chodzi o lokalizację komentarz może je rozpoczynać zarówno na początku linii (chyba najczęstsza praktyka), jak i w dowolnym innym miejscu wiersza. Niestety powłoka bash nie proponuje przy tym rozwiązania pozwalającego na tworzenie komentarzy wielowierszowych.
Zmiana – deklaracja oraz wywołanie
A teraz do sedna: zmienne w bash deklarowane są podobnie jak w Pythonie, czyli po prostu podajemy jakąś nazwę po czym następuje znak równości i po jego prawej stronie przypisujemy wartość, którą chcemy pod zmienną podstawić. Natomiast tutaj trzeba podkreślić wystąpienie pierwszego “dziwactwa” ze zmiennymi w bashy. Otóż między znakiem równości a nazwą zmiennej z jednej strony oraz przypisaną wartości z drugiej nie może być żadnych przerw (spacji). W przeciwnym razia interpreter “ucieszy” nasze oczy informacją o błędzie. Na pewnym poziomie abstrakcji wygląda to następująco:
nazwa_zmiennej=wartość zmiennej
zaś w praktyce – czyli w skrypcie – zobaczymy coś takiego na przykład:
autor=borciugner
Jak widać nie ma tutaj konieczności wskazywania wprost, że w tym miejscu odbywa się akt deklaracji zmiennej, choć nie jest prawdą, że w przypadku basha nie ma słowa kluczowego przewidzianego na tę okazję, który wskazywałby jednoznacznie oto jesteśmy świadkami powołania do życia zmienną (patrz niżej). Przyznam jednak, że ja sam nie używam takiej konstrukcji i chyba nie widziałem skryptu, którego autor miał taką potrzebę.
Jeśli chodzi o reguły rządzące tworzeniem nazw zmiennych, to również w tym przypadku powłoka bash pozwala na dużą swobodę, bowiem do dyspozycji mamy wszystkie znaki alfanumeryczne oraz symbol podkreślenia czy tam – jak mawia mój syn – podłogi. Należy jednak pamiętać, że nazwa zmiennej nie możem zaczynać się od cyfry oraz – oczywiście jak to unixach bywa – wielkość liter ma znaczenie.
A jeśli już przy tej ostatniej kwestii jesteśmy, to wspomnę o pewnej konwencji, która jest chyba dość powszechnie stosowana, czyli praktyce zapisywania nazw zmiennych raczej małymi literami niż dużymi. To dobry nawyk ponieważ chroni nas przed pomieszaniem naszych zmiennych ze zmiennymi systemowymi w rodzaju tych, które zdążyliśmy już poznać (np. HOME, PATH, USER itp).
Wywołanie tak spreparowanej zmiennej wymaga następnie użycia symbolu $, który należy wstawić przed nazwą zmiennej, co zresztą widzieliśmy w poprzednim wpisie, gdy używaliśmy zmiennej PATH. Ot cała filozofia (no może nie do końca – patrz ramka).
Koda, czyli finiszujemy
Do omówienia dzisiaj pozostała ostatnia kwestia, a mianowicie sposób przekazywania do zmiennej łańcuchów znaków składających się z kilku wyrazów albo inaczej rzecz ujmując: łańcucha znaków, który składa się między innymi ze spacji. W tym przypadku do dyspozycji mamy dwie metody, tj. z jednej strony zamknięcie ciągu znaków pomiędzy apostrofami, z drugiej zaś użycie do tego cudzysłowów. Osobiście w praktyce nie używam pierwszej z nich, ale gwoli kronikarskiej sumienności, napiszę, że ten sposób (apostrofy) pozwala nam przekazać interesujący nas ciąg do zmiennej lub innego polecenia w “oryginalnej” postaci, czyli bez żadnych modyfikacji ze strony interpretera. W przypadku cudzysłowów musimy być nieco ostrożniejsi, ponieważ “widząc” cudzysłów powłoka rości sobie prawo do pewnych specjalnych działań na tej treści. By to zobrazować użyjmy przykładu:
W efekcie w terminalu zobaczymy coś takiego:
Wołają na mnie $imie
Wołają na mnie Borciugner
Stało się tak dlatego, że w przypadku drugiego polecenia powłoka zinterpretowała (w tym przypadku prawidłowo, czyli zgodnie z naszymi intencjami) zapis $imie jako próbę wywołania takiej zmiennej. Jest to bardzo przydatna właściwość użycia cudzysłowów dlatego zalecam używania wyłącznie tej formy w celu wyrobienia w sobie odpowiedniego nawyku.
Ktoś się jednak zapyta, a co jeśli będziemy chcieli użyć znaku $ chociażby jako symbolu dolara, a przy tym umieścić to między cudzysłowami. Na tę okoliczność – podobnie jak w innych językach programowania – został pomyślany symbol ucieczki. W przypadku bash tę rolę spełnia tzw. odwrócony backslah (“\” – powinien się znajdować klawiszem “enter”). By się o tym przekonać wystarczy uruchomić taki prosty skrypcik:
Dwa słowa na zakończenie
Z przerażeniem stwierdzam, że wbrew pierwotnym założeniom teksty mojego autorstwa na temat skryptowania powłoki bash mają tendencje do nadmiernego rozrastania. Dlatego postanowiłem temat zmiennych podzielić na dwie części. W związku z tym dzisiejszy wpis dotyczył kwestii fundamentalnych dla tego zagadnienia, czyli głównie sposobu deklarowania zmiennych oraz podstawowych mechanizmów ich użycia. W kolejnym teście będę chciał poruszyć bardziej specyficzne dla bash zagadnienia w tym zakresie, czyli między innymi wykonywanie działań arytmetycznych oraz przekazywanie argumentów do skryptu. Będzie też bardzo krótko o tablicach oraz używania poleceń w zmiennych.