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