dla początkujących
BASH
64
październik 2006
dla początkujących
BASH
65
www.lpmagazine.org
a
ut
or
zy
@
lpm
ag
az
ine
.o
rg
Skrypty powłoki
w systemie Linux
Wykonywanie codziennych czynności w systemie operacyjnym jest męczące, gdy za każdym razem
trzeba wpisywać te same zestawy komend. Znacznie wygodniej byłoby zapisać je w plikach, które
możemy później uruchomić w dowolnej chwili. Pod Linuksem, dzięki możliwości tworzenia skryptów
powłoki (shella) wykonamy te zadania bez problemu; co więcej, znajomość shella bywa konieczna,
gdyż opiera się na nim duża część konfiguracji systemu....
Łukasz Sosna
S
krypty powłoki (shella) to ciągi jego instruk-
cji zapisane w postaci zwykłych plików teksto-
wych, które mogą zostać uruchomione w po-
włoce i wykonać za nas określone operacje. Taki
skrypt może też zawierać instrukcje warunkowe, pozwa-
lające m.in. przeprowadzić wybrane działanie po wpisa-
niu odpowiedniego parametru w linii poleceń (po nazwie
skryptu), pętle wykonujące zapisane przez nas instrukcje
określoną ilość razy czy wspomniane już argumenty po-
dawane w linii poleceń, które przekształcimy na zmienne,
którymi z kolei będzie można dowolnie manipulować.
Ponieważ powłoka traktuje skrypty jako zwykłe ko-
mendy, po każdym zapisanym w skrypcie poleceniu musi
być znak nowej linii: w przeciwnym razie skrypt zakończy
się niepowodzeniem. Ta sama zasada dotyczy instrukcji
warunkowych, pętli, itd, które wstawiamy do pliku. Po-
między instrukcją, a otaczającymi ją znakami bądź zmien-
nymi powinien też zostać zachowany odpowiedni odstęp.
Przykładowo, ten skrypt będzie zapisany prawidłowo:
#!/bin/bash
vdir /home
Natomiast ten jest nieprawidłowy, gdyż linia została zła-
mana w nieodpowiednim miejscu:
#!/bin/bash
vdir
/home
Pierwsza linia każdego skryptu musi zawierać wywołanie
shella, pod którym skrypt będzie wykonywany. Najpopu-
larniejszą powłoką dla systemu Linux jest bash, znajdujący
się najczęściej w katalogu z plikami binarnymi (/bin).
W podanych przykładach przedstawiliśmy zawartość tej
linii dla basha (
#!/bin/bash
). Pamiętajmy, że niezależnie
od typu shella, linia ta zaczyna się zawsze od znaku „#”.
Aby skrypt wykonywał się na naszym komputerze,
trzeba mu nadać odpowiednie uprawnienia. Ustawiamy
je za pomocą polecenia
chmod
i muszą one mieć wartość
7
dla osoby, która będzie wykonywała skrypt (owner, group
lub other). W naszych przykładach ustawimy te prawa na
7 dla wszystkich użytkowników, więc każdy będzie mógł
je uruchamiać; pamiętajmy jednak, że nie zawsze jest to
zalecane; czasem ze względów bezpieczeństwa warto wy-
dla początkujących
BASH
64
październik 2006
dla początkujących
BASH
65
www.lpmagazine.org
łączyć uprawnienia np. dla użytkowników
oznaczonych jako other. Oto przykładowe
wywołanie
chmod
:
chmod 777 skrypt
.
Nasz skrypt zapiszemy w pliku o nazwie
skrypt. Aby go wywołać, nie wystarczy wpisać
jego nazwy nawet będąc w tym samym kata-
logu, gdyż powłoka będzie szukała polecenia
o tej nazwie w ścieżce PATH i jeżeli go nie znaj-
dzie, zwróci błąd. Musimy podać pełną ścież-
kę dostępu do skryptu, zaczynającą się od /
– jeżeli jesteśmy w tym samym katalogu, wpi-
sujemy ./skrypt:
[lukasz@localhost ~]$ ./skrypt
Inną możliwością uruchomienia skryptu jest
wywołanie powłoki i wpisanie pliku ze skryp-
tem jako jej argumentu:
bash skrypt
Zamiast wpisywać nazwę powłoki, może-
my też użyć znaku kropki: wywołana zo-
stanie powłoka, w której aktualnie jesteśmy:
[lukasz@ localhost ~]$ . skrypt.
My będziemy korzystali z pierwszej me-
tody, gdyż jest ona najbardziej przystępna
i najczęściej używana przez programistów
w środowisku Linux.
Zmienne
Zmienne to oznaczone nazwami miejsca
w pamięci przechowujące pewne warto-
ści, które do nich przypiszemy. W powło-
ce istnieją zmienne mogące przechowywać
wartości logiczne, tekst i liczby. Zmien-
ne w bashu deklarujemy na bieżąco, przy-
pisując wartości za pomocą znaku „=”:
zmienna="tekst"
. Jeżeli chcemy przypisać
do zmiennej wartość zawierającą spacje, na-
leży ją umieścić w cudzysłowach (warto to
robić niezależnie od tego, czy tekst zawie-
ra spacje, bo zapobiega to wielu potencjal-
nym błędom) – inaczej mogą wystąpić błę-
dy. Przy deklarowaniu nie poprzedzamy
zmiennej żadnym znakiem specjalnym.
Jeżeli chcemy wyświetlić zawartość zmien-
nej, musimy poprzedzić jej nazwę znakiem do-
lara „$”:
#!/bin/bash
zmienna="tekst"
echo $zmienna
W innym wypadku nazwa zmiennej będzie po-
traktowana jako zwykły tekst i po prostu wy-
świetlona:
#!/bin/bash
zmienna="tekst"
echo zmienna
Wypisywanie tekstu na ekranie
Do wyświetlania tekstu na ekranie służy kil-
ka poleceń powłoki, z których najczęściej uży-
wamy
echo
:
#!/bin/bash
echo To jest tekst
Po wywołaniu skryptu ujrzymy napis
To jest
tekst
.
Wartości logiczne
Tak, jak w każdym innym języku programo-
wania, w bashu występują wartości logiczne:
TRUE
(prawda) i
FALSE
(fałsz). Są one reprezen-
towane za pomocą cyfr (
0
- prawda i 1 (lub ja-
kakolwiek inna niż
0
) – fałsz). Są one zwracane
przez różne polecenia i umieszczane w specjal-
nej zmiennej
$?
:
#!/bin/bash
vdir /home/lukasz
echo $?
Skrypt spróbuje wylistować katalog (może
się to nie powieść, jeśli nie mamy odpowied-
nich uprawnień dostępu) i pokaże informacje
o tym, czy udało się to wykonać:
[lukasz@localhost ~]$ ./skrypt
drwx------ 5 lukasz lukasz 4096 gru
29 19:50 Desktop
drwxrwxr-x 2 lukasz lukasz 4096 lis
24 2005 Dokumenty
0
Oto parametry polecenia
echo
, które nale-
ży podawać (w linii poleceń lub skrypcie)
przed tekstem do wypisania:
•
-n
na końcu linii nie będzie wypisywany
znak przejścia do nowej linii, więc tekst
wypisany przez kilka kolejnych
echo
zo-
stanie wyświetlony “ciurkiem”,
•
-e
pozwala zinterpretować wszystkie
znaki specjalne, które wpisujemy, po-
przedzając je znakiem backslash “\”,
•
-E
powoduje, że w wyświetlanym tek-
ście nie będą interpretowane znaki spe-
cjalne. Zostaną one pominięte, a powło-
ka wyświetli jedynie ich symbole,
•
\a
spowoduje pojawienie się alarmu
dźwiękowego na naszym komputerze
(głośniczek),
•
\b
po wyświetleniu tekstu cofa kursor
(pozycję końca tekstu) o jeden znak w le-
wo,
•
\n
powoduje pojawienie się nowego
wiersza po zakończeniu wypisywania
bieżącego,
•
\c
wypisuje znak nowego wiersza na
końcu linii,
•
\r
powoduje powrót karetki do począt-
ku wiersza po wypisaniu odpowiednie-
go fragmentu tekstu,
•
\t
powoduje pokazanie się znaku tabu-
lacji w poziomie,
•
\v
powoduje pokazanie się znaku tabu-
lacji w pionie,
•
\
powoduje pokazanie się znaku back-
slasha (\). Używamy dwóch backslashy
(\), aby wypisać jeden, gdyż normalnie
jest on znakiem sterującym,
•
\'
wypisuje znak pojedynczego apo-
strofu (analogicznie jak w przypadku
backslashy: apostrof jest z kolei ogra-
nicznikiem tekstu w zmiennych),
•
\”
pozwala wypisać podwójny cudzy-
słów (analogicznie jak w przypadku apo-
strofów),
•
\nnn
pozwala na wypisanie znaku z ta-
beli kodów ASCII o ósemkowej notacji
(gdzie
nnn
to kod znaku),
Parametry polecenia echo
Listing 1.
Blok instrukcji warunkowej if
z użyciem else
#!/bin/bash
a = 3
if [ “$a” = 3 ]
then
echo Wartosc zmiennej a wynosi 3
else
echo Wartosc zmiennej a jest
rozna od 3
fi
Listing 2.
Blok instrukcji warunkowej if
z użyciem elif i else
#!/bin/bash
a = 3
if [ “$a” = 3 ]
then
echo Wartosc zmiennej a wynosi 3
elif [ “$a” = 4 ]
echo Wartosc zmiennej a wynosi 4
else
echo Wartosc zmiennej a jest rozna
od 3 i od 4
fi
66
październik 2006
dla początkujących
BASH
67
www.lpmagazine.org
dla początkujących
BASH
Polecenie test
Polecenie
test
służy do testowania wyrażeń
logicznych, czyli porównywania wartości.
Ma ono wiele możliwości, np. pozwala
sprawdzić, czy
a
jest mniejsze od
b
, czy wy-
brany plik jest katalogiem lub czy łańcuch
tekstowy ma długość większą od
0
. Na przy-
kład efektem działania skryptu:
#!/bin/bash
test 2 -gt 3
echo $?
Będzie sprawdzenie, czy
2
jest większe (
-gt
od ang. greater) od
3
i zwrócenie wyniku, któ-
ry oczywiście jest fałszywy (
1
) i który wyświe-
tlimy używając
echo $?
. Większą listę para-
metrów
test
zamieszczamy w Ramce Parame-
try polecenia test.
Instrukcja if
If
to podstawowa instrukcja warunkowa
w bashu: testuje podane przy słowie
if
wy-
rażenie i jeżeli ono jest prawdziwe, wykonuje
blok kodu zawarty pomiędzy
then
a
fi
(
fi
jest
zakończeniem całego bloku
if
). Przykład:
#!/bin/bash
if [ 1 = 1 ]
then
echo Wartosci sa takie same
fi
Bardzo ważne są odstępy pomiędzy nawiasa-
mi kwadratowymi a instrukcją
if
i wyraże-
niem. Pamiętajmy też o konieczności ich za-
chowania z lewej i prawej strony znaku
=
. Nie-
stety, bash jest pod tym względem bardzo wy-
magający (możnaby powiedzieć, że sztywny
i nieprzyjazny) i niestosowanie się do tych za-
sad może zaowocować błędami. Pomiędzy
blokiem kodu wykonywanym przy spełnio-
nym wyrażeniu a słowem
fi
można wstawić
instrukcję
else
: zamieszczony w jej ramach
blok kodu zostanie wykonany przy niespeł-
nieniu wyrażenia podanego przy
if
. Oczywi-
ście, sprawdzanie wyrażeń typu
1 = 1
nie ma
żadnego sensu – lepiej jest użyć zmiennych czy
nazw plików, stosując te same operatory, co
w poleceniu
test
. Spójrzmy na Listing 1: spraw-
dzamy, czy zmienna a jest równa
3
. W wyraże-
niu używamy nazwy zmiennej poprzedzo-
nej znakiem
$
. Co więcej, otaczamy ją cudzy-
słowem, co zapobiega wielu przykrym niespo-
dziankom związanym ze specyficznym trakto-
waniem zmiennych przez basha.
Nic nie stoi na przeszkodzie, aby w jednym
bloku
if
zawrzeć więcej warunków: służy do
tego słowo
elif
(Listing 2), które pozwala do-
dawać kolejne wyrażenia (u nas: czy a jest równe
4?). Blok zapisany pod else zostanie wykonany
jedynie wtedy, gdy żadne z wymienionych
wyrażeń nie będzie spełnione (u nas: gdy
a
jest
różne zarówno od
3
, jak i od
4
).
Instrukcja case
Instrukcja
case
jest podobna do instrukcji
if
, ale różni się od niej składnią. Nic nie stoi
na przeszkodzie, aby używać obu instrukcji
zamiennie (
if
zamiast case i vice versa). Oto
składnia
case
:
case warunek in
odpoweidz1)
pierwszy blok kodu
;;
Esac
Spójrzmy na Listing 3, na którym zamieściliś-
my przykład użycia
case
. Jak widzimy, blok
case
zaczyna się od słowa
case
, a kończy na
esac
. Poszczególne warunki są oznaczone
prawymi nawiasami okrągłymi (np.
1)
,
2)
)
i oddzielone od siebie podwójnymi znakami
średnika (
;;
). Przy słowie
case
wymieniamy
zmienną (ponownie ze znakiem
$
na początku
i otoczoną cudzysłowami), której wartość bę-
dziemy sprawdzali oraz słowo kluczowe
in
.
Użycie gwiazdki (
*
) pozwala nam uwzględ-
nić wartości niewymienione w kolejnych wa-
runkach (u nas np.
67
).
Pętla while
Pętla
while
służy do powtarzania czynno-
ści w niej zawartych, a jej struktura jest na-
stępująca:
While polecenie
do
blok czynności do wykonania
done
Czynności zapisane w bloku kodu pomiędzy
słowami
do
i
done
będą powtarzane (iterowa-
ne) tak długo, aż warunek postawiony pętli nie
zostanie spełniony. Spójrzmy na Listing 4: zde-
finiowana na nim zmienna
i
ma początkową
wartość
0
. Następnie wartość ta jest wyświetla-
na w pętli
while
instrukcją
echo
i zwiększana
(inkrementowana) o 1 z każdym przebiegiem
pętli. Zawarte w nagłówku while wyrażenie
[ $i -lt 5 ]
powoduje, że instrukcje w pętli
będą wykonywane, aż zmienna
i
osiągnie
wartość
5
.
Pętla for
Pętla
for
, której konstrukcja jest inna niż
whi-
le
, powtórzy czynności zapisane w bloku po-
między
do
a
done
wobec każdego elementu li-
sty, którą jej podstawimy (może być nią też np.
tablica albo katalog na dysku). Jej konstrukcja
jest następująca:
Listing 3.
Przykład skryptu sprawdzającego jaką
wartość ma zmienna
#!/bin/bash
wartosc=1
case "$wartosc" in
1)
echo Liczba ma wartosc 1
;;
2)
echo Liczba ma wartosc 2
;;
*)
echo Liczba ma inna wartosc
;;
Esac
Listing 4.
Pętla while, która wyświetla liczbę
i zwiększa jej wartość o 1, aż do osiągnięcia 5
#!/bin/bash
i=0
while [ $i -lt 5 ]
do
echo $i
i=`expr $i + 1`
done
Listing 5.
Pętla for wyświetlająca w kolejnych
liniach nazwy systemów operacyjnych
#!/bin/bash
for system in Linux Windows MacOS
do
echo $system
done
Listing 6.
Polecenie continue nie pokazuje napi-
su „kolejny system” po systemie Linux
#!/bin/bash
for system in Windows Linux MacOS
do
echo $system
if [ "$system" = "Linux" ]
then
continue
fi
echo kolejny system
done
68
październik 2006
dla początkujących
BASH
For zmienna in lista
do
blok_kodu_do_wykonania
done
Spójrzmy na Listing 5. Przedstawiona tam pę-
tla
for
przypisze zmiennej
system
kolejne war-
tości. Każdą z nich wypiszemy używając
echo
,
uzyskując tym samym listę popularnych syste-
mów operacyjnych (każda nazwa w osobnej li-
nijce). Możemy też używać innej składni pętli
for
, przypominającej tę z języka C/C++:
for ((wyrażenie1; wyrażenie2;
wyrażenie3))
Przykładowo:
for ((licznik=5; licznik <= 23;
licznik++))
do
echo wartosc zmiennej licznik:
$licznik
done
W tym przypadku, w pierwszym przebiegu
pętli
for
zmiennej
licznik
zostanie przy-
pisana wartość
5
, która będzie wzrastać
z każdym kolejnym przebiegiem (decyduje
o tym
wyrażenie3
, w naszym przypadku
licznik++
), aż osiągnie wartość
23
.
Instrukcje continue i break
Polecenie
continue
wymusza przejście do na-
stępnego kroku w pętli (iteracji). Polecenia te-
go używamy z warunkiem, po którym ma się
ono wykonać, gdyż inaczej pętla się w ogóle
nie wykona. Spójrzmy na Listing 6. Po natra-
fieniu na nazwę
Linux
, pętla
for
przeskoczy
do następnego elementu, więc nie ujrzymy na-
pisu kolejny system. Polecenie
break
może za-
kończyć działanie dowolnej pętli, jeżeli poda-
my warunek jej zakończenia, np. liczbę po-
wtórzeń dla pętli. Przykład użycia
break
za-
mieściliśmy na Listingu 7: tym razem, po na-
Polecenie
test
wykorzystuje parametry
i operatory pozwalające wykonywać za-
awansowane porównania, np.:
•
-d
sprawdza, czy plik jest katalogiem
(
test -d nazwa_pliku
)
•
-f
sprawdza, czy plik ma prawa do wy-
konywania (
test -f nazwa_pliku
)
•
-L
informuje, czy plik jest dowiązaniem
symbolicznym do innego miejsca (
test
-L nazwa_pliku
)
•
-r
sprawdza, czy plik istnieje i czy są
mu nadane prawa do odczytu (
test -r
nazwa_pliku
)
•
-w
sprawdza, czy plik istnieje i są mu
nadane prawa zapisu (
test -w na-
zwa_pliku
)
•
-x
sprawdza, czy plik istnieje i czy są
mu nadane prawa do jego uruchomie-
nia (
test -x nazwa_pliku
)
•
-s
sprawdza, czy plik istnieje i czy jego
wartość nie jest zerowa (
test -s na-
zwa_pliku
)
•
-nt
porównuje daty zapisu i sprawdza,
czy czy
plik1
jest nowszy (ang. newer
than) od
plik2
(
test plik1 -nt plik2
)
•
-ot
sprawdza, czy plik1 jest starszy
(ang. older than) od plik2 (
test plik1
-ot plik2
)
•
=
sprawdza, czy ciągi znaków, zmien-
ne bądź liczby są identyczne, czyli rów-
ne sobie (
test liczba1 = liczba2
).
UWAGA: pomiędzy porównywanymi
wartościami a znakiem “=” muszą być
odstępy o długości jednej spacji z każ-
dej strony,
•
!=
sprawdza, czy ciągi znaków lub licz-
by po jego końcach nie są identyczne
(analogicznie jak
=
)
•
-z
sprawdza, czy ciąg znaków podany
po nim ma zerową długość (
test -z
ciąg_znaków
)
•
-n
sprawdza, czy ciąg podany za nim
ma niezerową długość (analogicznie
jak
-n
)
•
-eq
sprawdza, czy wartości liczbowe
(wyłącznie one) podane po jego obu
stronach są sobie równe (
test war-
tość1 -eq wartość2
)
•
-ne
sprawdza, czy wartości liczbowe po-
dane po jego obu stronach nie są iden-
tyczne (analogicznie jak
-eq
)
•
-gt
sprawdza, czy pierwsza wartość
liczbowa jest większa od drugiej (
test
liczba1 -gt liczba2
)
•
-ge
sprawdza, czy pierwsza wartość
liczbowa jest większa lub równa drugiej
(
test liczba1 -ge liczba2
)
•
-lt
sprawdza, czy pierwsza wartość
liczbowa jest mniejsza od drugiej (
test
liczba1 -lt liczba2
)
•
-le
sprawdza, czy pierwsza wartość
liczbowa jest mniejsza lub równa drugiej
(
test liczba1 -le liczba2
)
• Wykrzyknik (
!
) to znak przecze-
nia: stosujemy go, gdy chcemy uzy-
skać wynik odwrotny do wyniku tekstu
(TRUE zamiast FALSE lub vice versa)
Parametry polecenia test
Listing 7.
W tym skrypcie polecenie break koń-
czy działanie pętli po natrafieniu na słowo Linux
#!/bin/bash
for system in FreeBSD Linux Windows
do
echo $system
if [ "$system" = "Linux" ]
then
break
fi
done
trafieniu na nazwę
Linux
, pętla
for
zakończy
swoje działanie.
Argumenty z linii poleceń
Jak już wiemy, do skryptu bashowego może-
my przekazać argumenty, które umieszcza-
my za nazwą pliku ze skryptem (w linii po-
leceń albo innym skrypcie, gdyż możliwe jest
wywoływanie jednych skryptów z drugich).
Przykład:
./ulubiony_system super.
Do przekazanych wartości odwołujemy
się za pomocą specjalnych zmiennych numer-
cznych oznaczanych jako
$1
,
$2
,
$3,
itd. W na-
szym przykładzie, wartością
$1
będzie
super
.
Oto skrypt ulubiony_system:
#!/bin/bash
echo "System Linux jest $1”
W efekcie działania skryptu uzyskamy napis:
System Linux jest super
.
Podsumowanie
W tym artykule przedstawiliśmy podsta-
we możliwości tworzenia skryptów powło-
ki, które pomogą Ci zacząć przygodę z ba-
shem. Na omówienie wszystkich aspektów
tego shella nie wystarczyłoby miejsca nawet,
gdyby zajmował on cały magazyn Linux+.
Dodajmy, że skrypty bashowe są nie tylko
przydatne w automatyzowaniu powtarzal-
nych czynności (np. montowania i odmon-
towywania dysków, kasowania pamięci ca-
che przeglądarek internetowych czy porząd-
kowania plików tymczasowych), ale rów-
nież są wykorzystywane w instalacji i kon-
figuracji systemu Linux i jego elementów
(np. sieci). Warto się więc ich nauczyć, do
czego potrzebna jest długotrwała prakty-
ka: znając basha wykonasz każdą czynność
w Linuksie i cały system będzie pod Two-
ją komendą.