Zmienne środowiskowe i cudzysłowia

Parę razy pojawiły się wyrażenia \*.zip czy '*.tar'. Teraz przyszła pora, żebym wyjaśnił, co to jest.
Bash jest bardzo domyślnym programem, zamiast przesyłać do programu gwiazdkę i niech program sam sobie z nią radzi, bash rozwija gwiazdkę. Jak myślisz, co będzie efektem działania komendy echo *.html? echo wypisze wszystkie pliki z nazwami kończącymi się na .html. Bash postępuje w ten sposób także z pytajnikiem i nawiasami kwadratowymi. I o ile nie masz chyba wątpliwości do tego, jak jest traktowany znak zapytania (zastępowanie dowolnego jednego znaku), to nawiasy kwadratowe są używane tak samo, jak w wyrażeniach regularnych (oznaczają dowolny znak spośród wymienionych wewnątrz). Nawiasy klamrowe z kolei powodują powstanie jakby listy: echo lista{a,b,c,def} wypisze listaa listab listac listadef (dla zainteresowanych: to działa w bashu, ale w sh nie). Po przecinkach nie może być spacji.
Skoro bash tak "dziwnie" traktuje pewne symbole, to gdy chcesz jednego z nich użyć, musisz albo poprzedzić go backslashem (bardzo popularna praktyka w różnej maści językach skryptowych zaczerpnięta z języka C), albo ująć w cudzysłów. Ale cudzysłów cudzysłowiowi nie równy. Na ten przykład, gdy zastosujesz cudzysłów podwójny ", wewnątrz niego bash zastosuje rozwijanie zmiennych środowiskowych i interpretację sekwencji escape'owych (toto z backslashem), ale już nie rozwinie listy ani symboli wieloznacznych. Znaczy to tyle, że echo "Ala ma {kaca,kota} *" nie wypisze Ala ma kaca kota <lista plików>, ale Ala ma {kaca,kota} *. Natomiast cudzysłów podjedynczy ' (pod podwójnym) zabrania bashowi wszelkiej interpretacji, nawet sekwencji escape'owych. echo 'Test \\backslashy' wypisze Test \\backslashy, podwójny backslash, a nie pojedynczy. Zmienne środowiskowe również nie są rozwijane, więc jest to niezła metoda na przesłanie znaczka dolara (oprócz poprzedzenia go backslashem). Jest jeszcze trzeci rodzaj cudzysłowia: "forwardowy". Znaczek od tego znajduje się pod tyldą. To ustrojstwo powoduje przechwycenie standardowego wyjścia programu i umieszczenie go w miejscu komendy. Krótko mówiąc echo `which ls` wypisze /usr/bin/ls (czy jakoś tak, to zależy od położenia ls). Nic szczególnego, ten sam efekt byłby po wpisaniu samego which ls. Ale tutaj to nie which wypisuje na ekran, ale echo. Może inny przykład: ls -l `which find` powinien wypisać informacje o pliku /usr/bin/find. Tekst wewnątrz forwardowego cudzysłowia jest traktowany tak samo, jak wewnątrz podwójnego cudzysłowia. Ponadto sam cudzysłów forwardowy może być zastąpiony przez znaczki $( ) (przydatne przy pisaniu skryptów).
To teraz parę słów o zmiennych środowiskowych. W tych zmiennych bash przechowuje sporo informacji, na przykład nazwę użytkownika czy położenie katalogu domowego. Wypisać wszystkie zmienne i ich zawartości możesz komendą env. Zmiana wartości jest nie taka znowu trudna: wystarczy coś w stylu ZMIENNA="nowa wartosc zmiennej" i już masz zmienioną (albo utworzoną) zmienną ZMIENNA. [mała uwaga] Nazwy zmiennych mogą składać się zarówno z dużych liter, jak i z liter małych czy cyfr (a także innych znaków, ale z wtedy jest więcej kombinacji z używaniem takich zmiennych). Przyjęło się jednak, że nazwy są pisane dużymi literami - łatwiej je odróżnić od na przykład programów [/mała uwaga] Wyjmowanie wartości spod zmiennej polega na poprzedzeniu nazwy tej zmiennej znaczkiem dolara: echo $USER wypisze ci, jako kto jesteś aktualnie zalogowany (ta sama informacja mieści się jeszcze pod $LOGNAME). Inne ciekawe zmienne środowiskowe to $PWD, $OLDPWD, $HOME, $PATH, $MAIL i $PS1 (ta ostatnia odpowiada za tzw. prompt, czyli znaczek zgłoszenia gotowości). W zmiennej $PATH wymienione są katalogi, które będą przeszukiwane w poszukiwaniu poleceń. Jeśli dodasz tam . (kropkę), to również bieżący katalog będzie przeszukiwany, czyli nie będziesz musiał uruchamiać poleceń ./polecenie, będzie wystarczyć polecenie.
Jeszcze zostało mi słówko o samym rozwijaniu zmiennych przez bash. Otóż przy zamianie nazwy zmiennej na jej zawartość zamiast ciągów wystąpień spacji, tabulacji i enterów wstawiane są pojedyncze spacje. Spróbuj wydać takie polecenie:

[dozzie@hans ~]$ TEST="pierwsza
> druga
> trzecia"
[dozzie@hans ~]$ echo $TEST

Zgadnij, co wypisze drugie polecenie? pierwsza druga trzecia. Jeśli bash rozwinąłby zmienną $TEST zostawiając entery, to przesłany zostałby ciąg: pierwsza, [Enter], druga, [Enter], trzecia. Zatem echo dostałoby tylko parametr pierwsza, a pozostałe dwa byłyby potraktowane jak polecenia. Dlatego bash zamienia entery na spacje (a tabulacje idą niejako przy okazji). A co zrobić, jeśli chcesz posłać dane takimi, jakie są? Musisz ominąć jakoś to, że znak entera kończy polecenie. Czyli ująć zmienną w cudzysłów:

[dozzie@hans ~]$ TEST="pierwsza
> druga
> trzecia"
[dozzie@hans ~]$ echo "$TEST"

Zostały tylko nawiasy $[ ] i $(( )), które są zamiennikami (w kwestii zgodności: w bashu 2.02 jeszcze tych nawiasów nie było). Wewnątrz nich zmienne zawierające liczby będą traktowane jak liczby, czyli echo $(( 5 + 3 )) wypisze 8, a nie 5 + 3. Tylko że bash nie potrafi operować na liczbach zmiennoprzecinkowych (znaczy nie-całkowitych), a całe wyrażenie wewnątrz musi być całkowicie zgodne z regułami matematycznymi, na przykład wyrażenie

[dozzie@hans ~]$ TEST=""
[dozzie@hans ~]$ TEST="$[" $TEST * 2 ]

wywali błąd, bo zmienna $TEST rozwinie się do pustego słowa, a ile to jest "* 2"?
To by było na tyle, jeśli chodzi o zmienne środowiskowe i cudzysłowia


Dalsza część kursu
Poprzednia część kursu
Jadłospis