Programowanie w shellu (bash).doc

(44 KB) Pobierz
Programowanie w shellu (bash)

Programowanie w shellu (bash)
napisał: ZyGfryD, 08:04 17-12-2002,

W tym artykule opiszę programowanie w shellu bash. Dlaczego? Jest kilka powodów: jest najbardziej popularny, w systemie pliki inicjujące są w nim napisane np. w katalogu /etc/rc.d/. Również spotkałem się z opinią: ?jeżeli już piszesz programy w powłoce, to pisz je w powłoce Bourne?a?. Pisanie w innych powłokach jest bardzo podobne.
Wbrew pozorom programowanie w powłoce jest często przydatne i przyspiesza pracę w systemie, a zarazem jest całkiem proste. Ci, którzy używają na co dzień którejś z odmian Uniksa, na pewno potwierdzą to.
Jak wygląda program napisany w shellu? Może to być zwykły ciąg instrukcji taki jak:

if [ `ls -l /var/spool/mail/user | awk '{print $5}'` -gt 0 ]; then echo ?masz poczte?; fi

jednak jest to niewygodne, więc wszelkie większe instrukcje przechowujemy w pliku. Taki plik może zawierać polecenia połączone w potoki, przeadresowania, zmienne, instrukcje sterujące a nawet proste funkcje.
Zgodnie ze standardem POSIX taki plik rozpoczyna się od:

#!/bin/bash

ścieżki do interpretatora (w zależności od tego jaki chcemy używać) w pierwszej linii.
Nazwa pliku nie jest ważna, natomiast koniecznym jest nadanie atrybutu +x czyli uruchamianie . [Polecenie: chmod +x nazwa_pliku ? red.]
Taki plik od tej pory będzie nosił miano skryptu.
Pierwszy program mógłby mieć postać:

#!/bin/bash
echo ?Witaj Linuksie?

co spowoduje wypisanie tekstu ?Witaj Linuksie?.
Chcąc umieścić komentarz w skrypcie używamy znaku #, który mówi o tym, że znaki umieszczone za nim nie będą interpretowane. Pamiętaj: #!/bin/bash to nie komentarz.
Zmienne w skrypcie inicjujemy w prosty sposób pisząc: nazwa_zmiennej=wartość, a odwołujemy się do niej poprzez $nazwa_zmiennej, zmienną zerujemy poleceniem nazwa_zmiennej=.
Wynikiem wykonania tego skryptu pokazanego w przykładzie 1 będzie:

szczesliwy numer:5
5 szczesliwy numer:

oraz dwie puste linie. Wywołanie polecenia echo -n powoduje brak przejścia kursora do następnej linii.
Natomiast echo $liczba $tekst powoduje, że obie zmienne zostanę wydrukowane w tej samej linii.
Zauważmy, że zmienne nie mają typu, jak to ma miejsce w językach wysokiego poziomu.
Wczytywanie wartości do zmiennej z klawiatury odbywa się za pomocą polecenia read zmienna.

#!/bin/bash
echo -n ?podaj liczbe:?


#!/bin/bash
# to jest komentarz
liczba=5
tekst=”szczesliwy numer:”
echo -n $tekst
echo $liczba
echo $liczba $tekst
liczba=
tekst=
echo $tekst
echo $liczba

Przykład 1: Najprostsze polecenia użyte w skrypcie.


if [ $OSTYPE = ?Linux? ]
then
echo ?fajnie?
else
echo ?jakos to przezyje?
fi

Uwaga: za klamrą ?[? i przed ?]? powinien być odstęp.
Testować możemy także wartości zmiennych:

if [ $tekst1 = $tekst2 ]
then
echo ?takie same napisy?
fi

Sprawdzenie czy napisy są różne odbywa się za pomocą operatora !=.

if [ $zmienna ]
then
echo ?zmienna nie jest pusta?
fi
if [ -f $zmienna ]
then
echo ?plik: ?$zmienna? istnieje?
fi

Inne warunki to:

n ? napis ma długość większą od zera
z ? napis ma zerową długość
f ? plik istnieje
d ? plik jest katalogiem
r ? możesz czytać plik
w ? możesz pisać do pliku
x ? możesz uruchomić plik
s ? plik ma długość większą od zera
p ? plik jest łączem nazwanym

Sprawdzanie wartości liczbowych ma postać:

if [ $liczba -eq 5 ]
then
echo ?liczba jest równa 5?
else
echo ?liczba jest różna od 5?
fi

Możemy wykonywać testy takie jak:

eq ? równe liczby
ne ? nierówne liczby
gt ? większa niż
lt ? mniejsza niż
ge ? większa bądź równa
le ? mniejsza bądź równa

Dostępne są również operatory logiczne ! ? negacja, -a ? iloczyn (and), -o ? alternatywa.
Jeżeli mamy więcej warunków do sprawdzenia stosujemy instrukcję elif:

if [ warunek ]
then
polecenie(a)



#!/bin/bash
echo "Napisz cos”;
read l
case $l in
”a” ) echo "Litera a”;;
[A-Z] ) echo "Ktoras z duzych liter”;;
”Linuks” ) echo "Ulubiony system”;;
[Kk][Oo][Nn][Ii][Ee][Cc] ) echo "Do widzenia”;;
* ) echo "nie wiem co napisales” ;;
esac

Przykład 2: Wykorzystanie instrukcji case.


elif [ warunek ]
then
polecenie(a)
fi

Kolejną przydatną instrukcją jest instrukcja case. Wywołanie wygląda w ten sposób:

case $zmienna in
wzorzec1 ) polecenie(a);;
wzorzec2 ) polecenie(a);;
.
.
wzorzecn ) polecenie(a);;
* ) polecenie(a) domyślne;;
esac
*) oznacza, że żaden ze wzorców nie został wybrany i zostanie wykonane polecenie domyślne (przykład 2).

Pętla while ma postać:
while [ warunek ]
do
polecenie(a)
done

Jej działanie pokazuje przykład 3.
Ta pętla będzie się wykonywała dopóki nie podasz napisu ?koniec?. Czyli dopóki warunek jest spełniony.
Inną podobną w zapisie pętlą jest until. Zamiast while piszemy until. Pętla ta wykonuje się, gdy warunek nie jest spełniony. Zakończy się wtedy, gdy zostanie on spełniony. Porównajmy je (przykład 4).
Pętla z przykładu 4(a) będzie cały czas wypisywać tekst (przerwać skrypt można wciskając ^C [czyli Ctrl-C ? red.]), ponieważ zmienna $l jest większa od jeden, czyli warunek jest spełniony. W przypadku pętli z przykładu4(b) nie zostanie wyświetlony napis, ponieważ warunek jest spełniony.



#!/bin/bash
while [ "$x” !="„koniec” ]
do
echo -n "napisz cos”
read x
echo "nie o to mi chodzilo”
done

Przykład 3: Pętla while.





)
#!/bin/bash
l=2
while [ $l -gt 1 ]
do
echo $l” jest wieksze od 1"
done
(b)
#!/bin/bash
l=2
until [ $l -gt 1 ]
do
echo $l” jest wieksze od 1 a mimo to nie zobaczysz tego napisu”
done


Przykład 4: Porównanie pętli until i while.


Do dyspozycji mamy również instrukcę for.
Kożystamy z niej w następujący sposób:

for zmienna in lista
do
polecenie(a)
done



#!/bin/bash
for slowo in Ala ma kota
do
echo $slowo
done

Przykład 5: Pętla for.


Działanie tej instrukcji polega na tym, że ?zmienna? przybiera wartości po kolei podane w ?lista? jak w przykładzie 5.
Ten skrypt wydrukuje kolejno słowa ?Ala ma kota? w nowych liniach.
Jeżeli natomiast w tej instrukcji nie użyjemy listy i zapiszemy w ten sposób:

for zmienna
do
polecenie(a)
done

wtedy ?zmienna? będzie przyjmowała za wartości parametry podane w wywołaniu skryptu.
W pętlach while oraz for możesz używać instrukcji break i continue. Pierwsza z nich spowoduje wyjście z pętli do instrukcji następującej po niej, instrukcja continue powoduje przejście do początku pętli, do jej następnego przebiegu.



#!/bin/bash
function logo
{
echo "Logo programu”
echo "uzytkownik (c)”
}
logo
echo "tutaj inne instrukcje”
logo

Przykład 6: Funkcje w skrypcie.


Proste menu możemy stworzyć instrukcją select. Ma ona podobne wywołanie jak for.

select zmienna in lista
do
polecenie(a)
done

Menu to ma postać wyliczenia, pierwszy element ma numer 1. Chcąc wybrać określoną opcję wybieramy odpowiedni numer. Wtedy ?zmienna? ma wartość odpowiadającą n-temu elementowi z listy.
Instrukcje możemy pogrupować w funkcjach, co często upraszcza skrypt oraz pozwala zmniejszyć jego długość. Funkcję tworzymy w ten sposób:

function nazwa
{
polecenie(a)
}

a wywołujemy ją w skrypcie poprzez jej nazwę.
W przykładzie 6 funkcja logo zostanie uruchomiona raz na początku programu i raz na końcu.
Obliczanie wartości wyrażeń następuje za pomocą instrukcji expr, przy czym możemy używać operatorów arytmetycznych: +, -, *, /, logicznych & (and), | (or), ! (not). Przykłady:

a=5
b=6
c=`expr $a * $b`
echo $c

wynikiem będzie oczywiście 30, (pamiętaj o odwrotnych apostrofach).
Inkramentację możemy wykonać za pomocą expr: liczba=`expr $liczba + 1` lub prostszym zapisem:

liczba=$[liczba+1]. Instrukcję exit używamy najczęściej podczas wyjścia z programu (wykonującego się skryptu). Gdy zapiszemy exit 0, wtedy programy, które ewentualnie będą korzystać z naszych skryptów, będą wiedziały, że program wykonał się poprawnie. Jeżeli chcemy powiadomić te programy o jakimś błędzie, zwracamy wartość różną od zera. Gdy chcemy zakończyć działanie programu, naciskamy kombinację klawiszy Ctrl+C lub Ctrl+\.
W skryptach możemy zareagować na te sygnały za pomocą instrukcji trap polecenie sygnał(y).
Gdy w skrypcie użyjemy polecenia:

trap 'echo ?przerwanie programu?;echo ?koniec?;exit 1' 2 3

to podczas użycia klawiszy ^C lub ^\ zostaną wydrukowane napisy: ?przerwanie programu? i ?koniec? oraz zostanie zwrócony kod błędu.
Chcąc nauczyć się więcej, możesz przeanalizować skrypty dostępne w systemie. Najważniejsze znajdziesz w katalogu /etc/rc.d/, są to skrypty inicjalizujące system, uruchamiają programy niezbędne do jego działania. Zresztą zobaczysz sam, co one robią. Kolejnymi katalogami, do których powinieneś zajrzeć są: /usr/sbin/, /usr/bin/, /var/log/scripts/, /var/log/setup/, /usr/X11R6/bin/ itd. Czy plik jest skryptem, który nas interesuje, możesz sprawdzić poleceniem file nazwa_pliku. Interesują nas pliki typu: Bourne-Again shell script text lub Bourne shell script text. Możemy je znaleźć pisząc skrypt pokazany w przykładzie 7.

W moim systemie ten skrypt znalazł ponad 300 plików. Potężna lektura do nauki;)
Szegółowy opis powłok znajdziesz w manualach (man bash, man tcsh), jak również uruchamiając info gdzie jest opisany między innymi zsh.
Idealną książką do nauki pisania skryptów jest: ?Unix dla użytkowników DOS-u?, autor Kenneth Pugh, WNT.



!/bin/bash
pliki=`find / -mount` #szuka wszystkie pliki poza katalogami zamontowanymi i zapisuje je do $pliki
for plik in $pliki #wykonuje polecenia dla każdego pliku na li¶cie $pliki
do
if [ -f $plik ] #czy to jest plik
then #jeżeli tak to
{
rodzaj=`file $plik | grep Bourne` #czy to jest skrypt sh lub bash (czy łańcuch zawiera słowo Bourne)
if [ ”$rodzaj” != ”” ] #jeżeli tak (łańcuch nie jest pusty)
then #to
echo ”znalazlem skrypt: ”$plik #wypisz jego nazwę
echo $plik >> lista #zapisz j± do pliku „lista”
i=$[i+1] #policz te pliki
fi
}
fi
done
echo ”Znalazlem ”$i” skryptow” #napisz ile ich znalazłes

Przykład 7: Skrypt wyszukujący skrypt




Użyteczne polecenia zewnętrzne
Programy przydatne przy pisaniu skryptów:
• awk – potężne narzędzie do manipulowania wzorcami — koniecznie się z nim zapoznaj
• basename ścieżka — zwraca nazwę pliku z podanej ścieżki
• cat — wczytywanie plików i wyświetlanie na standardowe wyjście
• clear — czyszczenie ekranu
• cmp — porównywanie plików
• cut — wycinanie kolumn lub pól
• date — wyświetla datę i czas
• dirname ścieżka — zwraca nazwę katalogu ze ścieżki
• find ścieżka parametry — szukanie plików
• grep wzorzec plik(i) — wyszukuje wzorzec w pliku.
• hostname — sama nazwa mówi za siebie
• kill sygnał proces — wysłanie sygnału do określonego procesu (kill -l — lista sygnałów)
• last — ostatnio zalogowani
• more — często używany w potoku do zatrzymania wyświetlanego wyjścia (np: cat /etc/passwd | more)
• ps — wyświetla aktywne procesy
• pwd — wyświetla ścieżkę bieżącego katalogu
• sed — edytor strumieniowy, zamiana lub modyfikacja wierszy
• sleep czas — zatrzymanie, przez „czas”— określony w sekundach
• sort plik — sortowanie pliku
• strings — wyszukiwanie ciągów znaków np. w plikach binarnych
• w — wyświetla użytkowników zalogowanych
• wc — liczy znaki: -c, linie -l, słowa -w

To tylko część z nich, o każdym możesz dowiedzieć się więcej używając polecenia man program lub program --help.

 

Zgłoś jeśli naruszono regulamin