Skrypty w systemie UNIX


Z historycznego punktu widzenia, to własnie skrypty, pisane w powłokach (shell) systemu operacyjnego UNIX, są pierwowzorem dla programów wsadowych dla systemu operacyjnego DOS, a później również Windows. Sam system operacyjny był pisany w języku C, stąd często składnia poleceń, czy też same polecenia UNIX'a, są podobne do tego co można znaleźć w specyfikacji języka C. W przypadku skryptów pisanych w systemie UNIX obowiązują podobne zasady jak przy programach wsadowych pisanych w systemie Windows (DOS).

Zawartość poniższego skryptu została zaczerpnięta z materiałów przygotowanego przez: dra inż. Jeremiego Grykę i mgra inż. Grzegorza Świątka. Treść została nieznacznie zmieniona i dostosowana do materiału dla studentów I roku.

Podstawy przetwarzania potokowego

W UNIX'ie z procesami są związane strumienie standardowe: wejściowy (stdin), wyjściowy (stdout) i błędów (stderr). Zwykle strumień wejściowy jest skojarzony z klawiaturą, strumień wyjściowy zaś z oknem terminala. Można jednak spróbować to zmienić przekierować standardowe strumienie do innych plików. Służą do tego celu specjalne operatory: <,>, >>. Zwrot symbolu oznacza kierunek w którym będzie płynął strumień danych. Wynik działania kolejnych poleceń można ze sobą łączyć za pomocą operatora |. Na przykład standardowo za pomocą plecenia who wyświetlane są informacje o użytkownikach zalogowanych w systemie:
iris:prac/graniszw% who
mkedzior   pts/1        Apr  5 15:47    (nat-c.acn.pl)
nowikt     pts/2        Apr  5 14:58    (10.4.137.3)
tfortuna   pts/3        Apr  5 16:00    (pc218.sochaczew.sdi.tpnet.pl)
rbracha    pts/4        Apr  5 16:53    (icg)
krasuskj   pts/10       Apr  5 16:45    (pb47.lomianki.sdi.tpnet.pl)
miskiewm   pts/11       Apr  4 12:36    (10.4.160.3)
graniszw   pts/12       Apr  5 16:17    (31-mo3-6.acn.waw.pl)
graniszw   pts/13       Apr  5 16:20    (31-mo3-6.acn.waw.pl)
racisa     pts/14       Apr  5 17:11    (10.4.233.3)
krasuskj   pts/15       Apr  5 16:33    (pb47.lomianki.sdi.tpnet.pl)  
Polecenie sort porządkuje wiersze w podanym pliku. W przypadku wydania polecnia: who | sort wynik będzie następujący:
iris:prac/graniszw% who | sort
graniszw   pts/12       Apr  5 16:17    (31-mo3-6.acn.waw.pl)
graniszw   pts/13       Apr  5 16:20    (31-mo3-6.acn.waw.pl)
krasuskj   pts/10       Apr  5 16:45    (pb47.lomianki.sdi.tpnet.pl)
krasuskj   pts/15       Apr  5 16:33    (pb47.lomianki.sdi.tpnet.pl)
miskiewm   pts/11       Apr  4 12:36    (10.4.160.3)
mkedzior   pts/1        Apr  5 15:47    (nat-c.acn.pl)
nowikt     pts/2        Apr  5 14:58    (10.4.137.3)
racisa     pts/14       Apr  5 17:11    (10.4.233.3)
rbracha    pts/4        Apr  5 16:53    (icg)
tfortuna   pts/3        Apr  5 16:00    (pc218.sochaczew.sdi.tpnet.pl)
Widać wyraźnie, że w wyniku sortowania użytkownicy zalogowani w systemie zostali uporządkowani alfabetycznie (wg. loginu). Podobnie przetwarzanie potokowe można zastosować w przypadku innych poleceń, np.wyświetlić wszystkie procesy działające na danej maszynie i uporządkować je wg. numeru PID.

Rozwiązanie:


% ps -ef | sort -k2
Wykonanie tego polecenia powoduje sortowanie tego, co pojawi się w wyniku wykonania polecenia ps -ef, wg. drugiej kolumny (-k2). Można spróbować przekierować tak powstały strumień do pliku lub bezpośrednio na ekran, np. korzystając z poleceń:
% ps -ef | sort -k2 > ps.txt 
Wynik polecenia ps zostanie przekierowany do pliku ps.txt lub
% ps -ef | sort -k2 | more
Wynik polecenia zostanie wyświetlony i podzielony na strony.

1. Wstęp


Jednym z podstawowych narzędzi ułatwiających pracę w systemie UNIX są skrypty. Skrypty tworzy się używając języka właściwego dla danej powłoki systemowej (np. sh, csh) albo specjalnego języka skryptowego (np. perl, tcl). Składnia języków skryptowych jest bardzo podobna do składni języków wysokiego poziomu, przy czym podstawowe polenia w skrypcie mają postać zwykłych poleceń wydawanych w danej powłoce systemowej. Skrypty zapisuje się w plikach według prostych, ściśle określonych zasad. Plik zawierający skrypt dedykowany dla konkretnego języka powinien zaczynać się deklaracją odpowiedniego interpretera składni, np.:

#!/bin/sh
#!/bin/csh
#!/bin/perl


Pominięcie deklaracji interpretera spowoduje próbę wykonania skryptu przez bieżącą powłokę, co może zakończyć się niepowodzeniem, ze względu na różnice składni obsługiwanej przez różne interpretery. Ponadto podczas tworzenia skryptu należy zwrócić uwagę na prawa dostępu dla pliku zawierajacego treść skryptu (prawo execute). Treścią laboratorium będzie tworzenie skryptów dedykowanych dla powłoki sh (Bourn shell). Podstawy składni języka skryptów dla powłoki sh opisane są np. w manual'ach (man sh) i answerbook'u.

Zadanie 1.1 Utwórz i wykonaj skrypt drukujący na ekranie tekst: Hello, world!
                  - należy otworzyć plik w dowolnym edytorze
                  - należy wpisać do niego następującą treść:
                                           echo "Hello, world!"
                  - należy plik zamknąć i ustawić odpowiednie prawa:
                                           chmod u+x <nazwa pliku>
                  - należy wykonać skrypt poleceniem:
                                           ./<nazwa pliku>

Wewnątrz skryptu można deklarować zmienne środowiskowe, np.:

TMP=/tmp/my_tmp ,

do których odwołujemy się podając ich nazwę poprzedzoną znakiem '$'.

Zadanie 1.2 Utwórz i wykonaj skrypt następującej treści:

                                           TEKST="Hello, world!"
                                           echo $TEKST

2. Przekazywanie parametrów


Istnieją dwie proste metody przekazywania parametrów do skrypu:
   - poprzez parametry wywołania:
                    % <skrypt> <par1> ... <par#> ,
   - w trybie interakcyjnym.

Prametry przekazywane do skryptu w linii wywołania reprezentowane są poprzez cyfry od '0' do '9'.  Parametr oznaczony cyfrą '0' oznacza nazwę skryptu. Jeżeli liczba parametrów przekracza 10, to w celu odwołania się do tych parametrów stosuje się polecenie 'shift' podając jako parametr zakres przesunięcia. Operacja ta jest nieodwracalna.

Zadanie 2.1 Utwórz skrypt drukujący parametry wywołania, których powinno być więcej niż 10.

          ...
          echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
          shift 10
          echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9


          % ./<nazwa skryptu> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

Czy wszystkie parametry wywołania zostały wydrukowane? Jeżeli nie to jak należy poprawić skrypt aby wydrukować wszystkie parametry? Zmodyfikuj skrypt tak aby wszystkie parametry były drukowane w jednej linii.

Aby przekazać do skryptu parametry w trybie interakcyjnym należy użyć polecenia 'read' podając jako parametr nazwę zmiennej, której chcemy nadać wartość. W jednej linii można wczytać więcej niż jeden parametr. Wczytanie parametru można poprzedzić komentarzem.

Zadanie 2.2 Utwórz skrypt wczytujący dwa parametry.

          echo Podaj parametry a i b:
          read a b

- Uzupełnij skrypt tak, aby drukował wprowadzone wartości.
- Zmodyfikuj skrypt tak, aby komentarz i wprowadzane dane znajdowały się w jednej linii. W tym celu zapoznaj się z manualami do polecenia 'echo ' oraz 'printf'.

3. Instrukcja warunkowa 'if'

Konstrukcja polecenia 'if' jest zbliżona do tych znanych z języków wysokiego poziomu.

Zadanie 3.1 Wykorzystując skrypt z poprzedniego zadania utworz skrypt porównujący dwie wartości i drukujący wynik.

          if [ "$a" = "$b" ]
           then
            echo rowne
           else
            echo nierowne
          fi


- Zwróć uwagę na konstrukcję linii warunkowej oraz sposób zamykania polecenia.
- Zmodyfikuj skrypt tak, aby cała instrukcja warunkowa znajdowała się w jednej linii.
- Zmodyfikuj skrypt tak, aby drukował wynik tylko wtedy, gdy oba parametry są od siebie różne.
- Zmodyfikuj skrypt tak, aby porównywał wartości numeryczne typu 'integer'.

Zadanie 3.2 Przeczytaj w manualu do powłoki albo do polecenia 'if' jakie są jeszcze inne rodzaje warunków. Zwróć szczególną uwagę na warunki dotyczące plików i napisz skrypt sprawdzający różne cechy plików.

UWAGA: Począwszy od tego miejsca w celu sprawdzenia sposobu użycia poszczególnych poleceń można odwoływać się do treści skryptów systemowych znajdujących się w katalogu '/etc/init.d'.

4. Pętla 'for'

Budowa pętli for jest nastepująca:

for <parametr> in <lista słów> do <lista poleceń> done

Przykład:

          for i in 1 2 3 4 5 6
          do
           echo $i
           sleep 1
          done


W wyniku wykonania powyższej instrukcji na ekranie będą drukowane kolejne liczby od 1 do 6, każda w osobnej linii, w odstępach jedno sekundowych (polecenie sleep).

Zadanie 4.1 Utwórz skrypt odliczający wstecz tak, aby otrzymać na ekranie wydruk postaci:

6...5...4...3...2...1...KONIEC

Zadanie 4.2 Utwórz skrypt drukujący długi listing zwykłych (nie będących katalogami) plików(!) w bieżącym katalogu.
Podpowiedź: listing wszystkich plików można uzyskać pisząc przykładowo:

	for i in * 
do
ls -l $i
done

5. Pętla 'while'

Budowa pętli while jest nastepująca:

while <lista warunków> do <lista poleceń> done

Przykład:

          while read a
          do
           if [ $a -eq 0 ]
           then
            exit
           fi
          done

W tym przypadku $a -eq 0 sprawdzane jest, czy zmienna a jest równa 0.

6. Instrukcja warunkowa 'case'

Budowa instrukcji case jest następująca:

case <słowo> in
<przykład>)
   <lista poleceń>
   ;;
<przykład>|<przykład>)
   <lista poleceń>
   ;;
*)
   <lista poleceń>
   ;;
esac

Przykład
#!sh
printf "To jest moj skrypt\n";
printf "Prosze wpisac jakis znak\n";
read tmp
case $tmp in
a | A ) echo 'Wpisano A' ;;
b | B ) echo 'Wpisano B' ;;
c | C ) echo 'Wpisano C' ;;
d | D ) echo 'Wpisano D' ;;
e | E ) echo 'Wpisano E' ;;
esac
Proszę zwrócić uwagę, że skrypt ten wypisuje daną literę bez względu na wielkość znaku jaki został wpisany.
Zadanie 6.1 Utwórz skrypt, którego zadaniem będzie czytanie ciągu znaków z ekranu i drukowanie jakiejś informacji (np. jaki znak został wczytany) albo zakończenie działania w zależności od wczytanej wartości.

Waldemar Graniszewski

Ostatnia modyfikacja: