Programowanie w Shellu (index)


Programowanie w Shellu (4) - konstrukcje warunkowe

ZADANIE 4.1

Zbadać zachowanie polecenia test.


$ help test | less
$ man test
$ test -r plik1     (sprawdzamy nieistniejący plik)
$ echo $?           (sprawdzenie kodu powrotu)

$ test -d /etc      (sprawdzenie istnienia katalogu)
$ echo $?           (sprawdzenie kodu powrotu)

$ test -d /etc && echo "to katalog"

$ if [ -d /etc ] ; then echo "to katalog" ; fi

$ test "abc" = "def"          (porównanie napisów)
$ echo $?           (sprawdzenie kodu powrotu)

$ test -f /etc/passwd -a -r /etc/passwd
    (czy plik zwykły i czy mamy prawo czytania
$ echo $?           (sprawdzenie kodu powrotu)

$ printenv PLIK_LOG           (sprawdzenie stanu zmiennej)
$ if [ -z "${PLIK_LOG}" ] ; then PLIK_LOG="sesja.log" ; fi
    (ustawienie zmiennej, jeżeli jest pusta)
$ printenv PLIK_LOG           (sprawdzenie wyniku podstawienia)

ZADANIE 4.2

Stworzyć plik bc.sh postaci:


#!/bin/bash
#
# bc.sh
#
# Nakładka na polecenie "bc", zwracająca wynik działania.

if [ "$1" = "-p" ] ; then
    PRECISION=$2
    shift 2         # przesuniecie numeracji argumentow
else
    PRECISION=2     # wartosc domyslna
fi

bc -q -l << EOF
scale=${PRECISION}
$*
quit
EOF

exit 0

Uruchomić skrypt poleceniami:


$ ./bc.sh  12/456
$ ./bc.sh -p 6 12/456

Zapoznać się z możliwościami kalkulatora bc.

ZADANIE 4.3

Stworzyć plik miesiac.sh postaci:


#!/bin/bash
#
# miesiac.sh
#
# Skrypt tlumaczacy skrot na pelna nazwe miesiaca.
# Wykorzystanie konstrukcji warunkowej "case".

echo -n "Podaj numer lub skrot miesiaca: "
read MIESIAC

case ${MIESIAC} in
1|01|Jan*) echo "${MIESIAC} to January (styczen)" ;;
2|02|F*) echo "${MIESIAC} to February (luty)" ;;
3|03|Mar*) echo "${MIESIAC} to March (marzec)" ;;
4|04|Ap*) echo "${MIESIAC} to April (kwiecien)" ;;
5|05|May) echo "${MIESIAC} to May (maj)" ;;
6|06|Jun*) echo "${MIESIAC} to June (czerwiec)" ;;
7|07|Jul*) echo "${MIESIAC} to July (lipiec)" ;;
8|08|Au*) echo "${MIESIAC} to August (sierpien)" ;;
9|09|S*) echo "${MIESIAC} to September (wrzesien)" ;;
10|O*) echo "${MIESIAC} to October (pazdziernik)" ;;
11|N*) echo "${MIESIAC} to November (listopad)" ;;
12|D*) echo "${MIESIAC} to December (grudzien)" ;;
*) echo "Nieznany miesiac";;
esac

Uruchomić skrypt poleceniem: ./miesiac.sh

TEST - SPRAWDZANIE PLIKÓW


Typy plików

[ -f plik1 ]        (plik1 istnieje i jest plikiem zwyklym)
[ -d plik1 ]        (plik1 istnieje i jest katalogiem)
[ -b plik1 ]        (plik1 istnieje i jest urządzeniem blokowym)
[ -c plik1 ]        (plik1 istnieje i jest urządzeniem znakowym)
[ -h plik1 ]        (plik1 istnieje i jest dowiązaniem symbolicznym)
[ -p plik1 ]        (plik1 istnieje i jest łączem nazwanym [pipe])
[ -L plik1 ]        (plik1 istnieje i jest łączem nazwanym [pipe])
[ -S plik1 ]        (plik1 istnieje i jest gniazdem [socket])
[ -t 1 ]            (standardowym wyjsciem jest terminal)

Prawa dostępu do plików (wybrane)

[ -r plik1 ]        (plik1 istnieje i mamy do niego prawo czytania)
[ -w plik1 ]        (plik1 istnieje i mamy do niego prawo pisania)
[ -x plik1 ]        (plik1 istnieje i mamy do niego prawo wykonywania)
[ -s plik1 ]        (plik1 istnieje i ma rozmiar wiekszy niz zero bajtow)

Właściwości plików

[ -e plik1 ]             (plik1 istnieje)
[ -s plik1 ]             (plik1 istnieje i ma rozmiar większy niż zero)
[ plik1 -nt plik2 ]      (plik1 jest nowszy niż plik2)
[ plik1 -ot plik2 ]      (plik1 jest starszy niż plik2)
[ plik1 -ef plik2 ]      (plik1 i plik2 są wzajemnie dowiązaniami sztywnymi)

TEST - SPRAWDZANIE ŁAŃCUCHÓW ZNAKOWYCH

Łancuchy dobrze jest umieszczać w cudzysłowach. Wtedy nawet pusta zmienna (lub nieustawiona) bedzie dobrze przetworzona.


[ s1 ]              (łańcuch s1 nie jest pusty)
[ -n s1 ]           (długość łańcucha s1 nie jest zerowa)
[ -z s1 ]           (długość łańcucha s1 jest zerowa)
[ s1 = s2 ]         (łańcuchy s1 i s2 są identyczne; ODSTEPY!)
[ "${ZMIENNA1}" = "${ZMIENNA2}" ]            (stosowanie cudzysłowu)
[ s1 != s2 ]        (łańcuchy s1 i s2 nie są identyczne)
[ s1 < s2 ]         (łańcuch s1 sortuje się przed s2)
[ s1 > s2 ]         (łańcuch s1 sortuje się po s2)

TEST - OPERACJE DLA LICZB CAŁKOWITYCH


[ int1 -eq int2 ]             (=, equal to)
[ int1 -gt int2 ]             (>, greater than)
[ int1 -ge int2 ]             (>=, greater than or equal to)
[ int1 -lt int2 ]             (<, less than)
[ int1 -le int2 ]             (<=, less than or equal to)
[ int1 -ne int2 ]             (<>, not equal to)

TEST - SPÓJNIKI LOGICZNE

[ ! expr1 ]                   (not)
[ expr1 -a expr2 ]            (and)
[ expr1 -o expr2 ]            (or)

KONSTRUKCJE Z || i &&


polecenie1 && { polecenie2 ; polecenie3 ;}

Forma równoważna z if jest dłuższa:

polecenie1
if [ $? -eq 0 ] ; then
    polecenie2
    polecenie3
fi

polecenie1 || polecenie2 

Forma równoważna z if:

polecenie1
if [ $? -ne 0 ] ; then
    polecenie2
fi

INSTRUKCJA IF-THEN-ELSE

Kod powrotu 0 polecenia oznacza true (prawdę). Zwykle polecenie to instrukcja test w postaci z nawiasami kwadratowymi [ ... ].


if polecenie ; then 
    lista poleceń
elif polecenie ; then         (opcja)
    lista poleceń
else                          (opcja)
    lista poleceń
fi

if polecenie ; then polecenie ; fi      (postać minimalna)

if polecenie ; then polecenie ; else polecenie ; fi

if polecenie ; then polecenie ; elif polecenie ; then polecenie ; fi

if polecenie ; then polecenie
elif polecenie ; then polecenie
elif polecenie ; then polecenie
elif polecenie ; then polecenie
else polecenie ; fi
    (ta postać może zastąpić instrukcję "case")

INSTRUKCJA CASE

Generalnie instrukcja case nie jest polecana w różnych językach programowania, ale w shellu się przydaje. Zawsze powinno się umieszczać na końcu akcję domyślną.


case ${ZMIENNA} in
wartosc1)                     (ważna jest kolejność podawanych warunków)
    lista poleceń
    ;;
wartosc2|wartosc3)            (można podać kilka wzorców)
    lista poleceń
    ;;
*)                            (można używać metaznaków)
    polecenia domyślne        (jako ostatnie)
    ;;
esac

Zamiast wyrażenia ${ZMIENNA} można użyć każdego wyrażenia, które daje w wyniku napis, np. wynik jakiegoś polecenia $(ls x*).

INSTRUKCJA read

help read
    (pomoc dla polecenia wewnętrznego powłoki)

read LINE
    (wczytanie całego wiersza ze stdin do zmiennej LINE)
read
    (wczytanie wiersza do zmiennej REPLY)
read ZMIENNA1 ZMIENNA2 ZMIENNA3
    (wczytanie kolejnych napisów do ZMIENNA1, ZMIENNA2,
    a reszty do ZMIENNA3)

Typowe zastosowanie w skrypcie:
echo -n "Podaj napis: "
read NAPIS

Można jeszcze prościej (opcja [-p prompt]):
read -p "Podaj napis: " NAPIS

Można wczytywać do zmiennych dane z pól oddzielonych innym znakiem
niż te ze zmiennej IFS (opcja [-d delim]):
read -d ":" POLE1 POLE2 POLE3

Programowanie w Shellu (index)