Řízení běhu skriptu
Následující programovací techniky jsou určeny pro Bourne shell (bash). Něco z toho
(hodně z toho) bude pracovat i v starší verzi sh
nebo jiných shellech, ale je to
potřeba vždy prověřit.
Řídící struktury shellu
Cyklus for
SYNOPSIS
for prom [ in seznam_hodnot ] do prvni_prikaz druhy_prikaz . . posledni prikaz done
Posloupnost prikazu mezi klicovymi slovy do
a done
se cyklicky opakuje.
Hodnoty ridici promenne prom se prirazuji ze seznamu, ktery je uveden za
klicovym slovem in, dokud nejsou vycerpany, nebo neni cyklus nasilne ukoncen (pomoci break
).
EXAMPLES
Vypise jmena a obsah vsech souboru s priponou .txt
v aktualnim adresari:
do
echo $i
cat $i
done
Jinak zapsáno totéž:
Seznam hodnot mohou byt argumenty prikazove radky $1, $2, $3, … Maji-li byt
hodnotami vsechny argumenty, potom zapis for i in $*
lze zapsat jako
for i
.
Cyklus while
SYNOPSIS
while prvni_prikaz druhy_prikaz . . . posledni_prikaz do prvni_prikaz . . posledni_prikaz done
Posloupnost prikazu mezi klicovymi slovy do
a done
se cyklicky opakuje
dokud posledni prikaz ze seznamu prikazu uvednych za while vraci nulovy navratovy kod, tzn. konci uspechem.
(Predchozi prikazy po while
nemaji na cyklus zadny vliv).
EXAMPLES
Program pro vytvoreni vice kopii z jednoho souboru. Prvni argument je jmeno kopirovaneho souboru, dalsi argumenty jsou jmena kopii:
while test $# -gt 1
do
cp $1 $2
shift
done
test $# -gt 1
testuje počet (zbývajících argumentů). -gt
zamená větší než (greather than).
Výpis čísel od 1 do 2:
$ while [ $B -lt 3 ]; do echo $B; B=$[$B+1]; done
[ $B -lt 3 ]
testuje, zda je $B menší (lower than) 3. Příkaz test
z předchozího příkladu
a test pomocí hranatých závorek jsou jen jiný způsob zapsání téhož.
Cyklus until
SYNOPSIS
until testovany_prikaz do prvni_prikaz druhy_prikaz . . posledni_prikaz done
Prikaz while
opakuje prikazy tak dlouho, dokud testovany_prikaz vraci hodnotu
true. Prikaz until naopak dokud testovany_prikaz vraci false. Jakmile vrati
true, cyklus se ukonci.
EXAMPLES
Cyklus čekající na vznik souboru data. Vznik souboru testuje každých 5 minut.
do
sleep 300
done
Srovnání příkazů while a until:
do do
echo $1 echo $1
shift shift
done done
Podmíněný příkaz if
SYNOPSIS
if prvni_prikaz druhy_prikaz . . posledni_prikaz # napr. viz. dale prikaz test then prvni_prikaz . posledni_prikaz [ else prvni_prikaz . posledni_prikaz ] fi
Posloupnost prikazu za klicovym slovem then se provede, kdyz posledni prikaz ze
seznamu prikazu uvedenych za if
vraci nulovy navratovy kod, tzn. konci uspechem.
Pokud konci neuspechem a konstrukce obsahuje nepovinnou cast else
, provede se
posloupnost prikazu za else
, pokud ji neobsahuje, pokracuje se dasim prikazem za
klicovym slovem fi
.
Konstrukce prikazu if
ve vetvi else
lze nahradit vyrazem elif
(else if).
EXAMPLES
if (test $# = 0) # zavorky jsou zde pouzity jen pro vetsi nazornost
then
echo Musite zadat aspon jeden argument
exit 1
fi
echo Konec scriptu
echo -e "slovo1: \c" # misto "\c" se da pouzit echo -n "slovo1: "
read s1
echo -e "slovo2: \c"
read s2
if (test "$s1" = "$s2") # všiměte si uvozovek kolem proměnných
then
echo Slova jsou stejne
else
echo Slova jsou ruzne
fi
echo Konec skriptu
Logické spojky
- prikaz1 && prikaz2
- prikaz2 se vykona pouze tehdy, vrati-li prikaz1 true
- prikaz1 || prikaz2
- prikaz2 se vykona, vrati-li prikaz1 hodnotu false
Logické spojky lze s výhodou používat i na příkazové řádce, např:
Přepínač case
SYNOPSIS
case ret in vzor_1) prvni_prikaz . . posledni_prikaz ;; . . vzor_n) prvni_prikaz . . posledni_prikaz ;; *) prvni_prikaz . . posledni prikaz ;; esac
Provede se pouze ta vetev, kde se vzor shoduje s textovym retezcem ret
.
Pokud neni shoda s zadnym vzorem, tak vzor *
je splnen vzdy (obdoba
expanzniho znaku *
, ktery nahrazuje libovolny retezec znaku). Dalsi pouzitelne
vzory jsou: ?
(jeden znak) [..]
(prave jeden ze znaku uvnitr zavorky, nebo s pomlckou
urcuje interval znaku) a |
(oddeluje jednotlive moznosti, ktere vyhovuji urcite vetvi)
EXAMPLES
echo -n "Chcete soubor opravdu vymazat? [a/n]: "
read znak
case $znak in
a|A) rm soubor ;;
n|N) ;;
*) echo "Neplatna odpoved" ;;
esac
Příkazy break, continue a : (dvojtečka)
Break
Návěstí break
způsobí ukončení cyklu (while, until, for).
Zpusobi vystup z cyklu a pokracovani interpretace skriptu za telem cyklu.
Continue
Návěstí continue
zpusobi ignorovani zbytku tela cyklu a prechod na dalsi
iteraci (dalsi pruchod cyklem).
: (dvojtečka)
Dvojtečka :
neprovádí žádnou činnost a vrací true.
Využívá se například v cyklech while
, nebo v příkazu trap
.
EXAMPLES
Nekonečný cyklus:
do
...
done
Příkazy test a expr
Příkaz test
Prikaz test
je pomocnym prikazem pro ridici struktry shellu. Jeho navratova
hodnota je dana vyhodnocenym vyrazem. Ma format: test vyraz
kde vyraz muze vyjadrovat vztahy textovych retezcu a atributy souboru. Pomoci
operatoru !
lze kazdy podvyraz negovat.
Testování souborů
-r soubor soubor existuje a je dostupny (ma pravo) pro cteni -w soubor soubor existuje a je dostupny pro zapis -x soubor a ma povoleny pristup pro spousteni -f soubor a je to obycejny soubor -d soubor a je adresarem -c soubor a je to specialni znakovy soubor -b soubor a je to blokovy specialni soubor -p soubor a je to pojmenovany kanal (pipe) -u soubor ma nastaven set user ID bit -g ma nastaven set group ID bit -k ma nastaven sticky bit -s a jeho velikost je vice nez 0 bajtu -t deskriptor otevreny soubor s cislem deskriptoru. Deskriptor je spojen s terminalem. Pokud deskriptor neni uveden, predpoklada se 1 (standardni vystup).
Testování řetězců
s1 retezec s1 neni prazdny retezec -z s1 delka textoveho retezce s1 je nulova -n s1 s1 je vetsi nez nula s1 = s2 retezce s1 a s2 jsou si rovny s1 != s2 retezce s1 a s2 si nejsou rovny
Logické operátory
vyraz -a vyraz2 oba vyrazy jsou pravdive ( logicky soucin ) vyraz -o vyraz2 alespon jeden vyraz je pravdivy ( logicky soucet )
Porovnání celých čísel
n1 op n2 vyhodnoceni algebraickeho porovnani celych cisel. Za op lze dosadit: -eq rovnost -ne nerovnost -gt vetsi nez -ge vetsi nebo rovno -lt mensi nez -le mensi nebo rovno
Nová syntaxe
Příkaz test vyraz
lze v nových shellech (nové verzi bashe) nahradit konstrukcí
[ vyraz ]
(mezery kolem hranatých závorek jsou nutné!)
# je totéž co
if [ "s1" != "s2" ]; then
Příkaz expr
Druhym pomocnym prikazem je expr
, ktery vyhodnocuje sve argumenty jako
aritmeticky vyraz.
SYNOPSIS
expr arg [arg ...]
Kazdy clen vyrazu je povazovan za zvlastni argument arg (musi byt oddeleny mezerou).
Příkaz expr
slouzi k vyhodnocovani vyrazu. Vyraz je slozen z dalsich
vyrazu a retezcu oddelenych mezerou. Poradi priorit lze menit zavorkami.
Argumenty mohou vyjadrovat nasledujici operace:
- op + op
- součet argumentů
- op - op
- op * op
- op / op
- celočíselné dělení
- op % op
- zbytek po celočíselném dělení
- op rop op
- Porovnávací operátor rop je jeden z relačních operátorů:
<,<=,=,!=,>=,>
Mezery mezi operandy a operátorem jsou nutné.
Tyto operátory pracují jak s numerickými, tak řetězcovými hodnotami. - op : regexp
- operator porovnani - porovnava retezec s regularnim vyrazem. Pokud dojde ke shode, zobrazi se pocet znaku schodnych s reg. vyrazem, jinak 0.
- op & op
-
logicky soucin - pokud zadny z argumentu nema hodnotu 0 nebo to neni
prazdny retezec, zobrazi hodnotu 1. argumentu.
Operator se musi oznacit. - op | op
-
logicky soucet - vyhodnoti svuj prvni argument. Jestlize to neni 0 ani
prazdny retezec, zobrazi hodnotu 1. argumentu.
V opacnem pripade zobrazi hodnotu 0.
Operator se musi oznacit.
Porovnávání v relačním výrazu je numerické, pokud jsou oba výrazy celočíselno. Jinak lexikografické (podle ASCII).
EXAMPLES
$ krok=`expr $krok + 1`
$ echo $krok
2
Konstrukce prikazu expr
musi byt v obracenych apostrofech, protoze produkuje
vysledek na standardni vystup. Jedna se tedy o klasicke nahrazeni prikazu svym
vystupem.
24
$ x=3
$ expr $x = 3
1
$ expr boj : bojkot
0
$ expr bojkot : boj
3
$ X=abc
$ expr $X : '.*'
3 # pocet znaku v retezci X
Nová syntaxe
expr vyraz
lze nahradit konstrukcí $((vyraz))
, která se vyhodnotí mnohem rychleji.
(Nemusí se používat obrácené apostrofy).
$ x=$(($x+1)) # kolem operatoru nemusi byt mezery
Příkaz trap a kill
Příkaz trap
zachytava signaly, tj. zpravy zaslane procesu,
ktere proces inforumuji o vyskytu nejake udalosti.
Zprávy lze posílat programem kill
.
SYNOPSIS
trap [[posloupnost_prikazu] seznam_signalu] kill {-l|-s id}
Pokud je posloupnost_prikazu -
(pomlcka), pak se drive
nastavena posloupnost signalu vynuluje.
Spuštění trap
bez argumentů vypíše nastavené příkazy pro signály.
Příkaz kill
pošle signál procesu zadaného ID, přičemž za s
se dosazuje číslo signálu. Volba -l
vypíše všechny možné signály.
SIGNALY
- 0
- ukonceni shellu (z libovolnych duvodu, napriklad prikazem
exit
) - 1
- odpojeni se od terminalu
- 2
- SIGINT - signal preruseni (interuption), napr. pomoci CTRL+c
- 3
- konec s ulozenim obsahu pameti
- 9
- nasilne bezpodminecne ukonceni procesu. POZOR! Tento signal nelze chytit ani ignorovat.
- 15
- Softwarove ukonceni.
Posloupnost prikazu je jediny argument, a proto je-li prikazu vice, musi byt uzavreny v uvozovkach nebo apostrofech.
Seznam signalu jsou cisla signalu, pri jejichz zachyceni se provedou dane prikazy.
Pokud shell zachyti dany signal, prerusi vykonavani skriptu, provede zadanou posloupnost prikazu a pokracuje v miste, kde byl skript prerusen (pokud není ukončen).
EXAMPLES
$ kill -2 $$
PROGRAM PRERUSEN
Pokud bezi skript na popredi, CTRL+c vygeneruje signal cislo 2 a skript ukonci. V nasem skriptu se misto toho signal zachyti a provede se prikaz v uvozovkach (echo).
Prikazy trap
a while
budou vykonany v samostatnem shellu - to
zpusobi zavorky - a pobezi na pozadi (pouziti spicatych zavorek by znamenalo beh programu v aktualnim
shellu). Pokud se uzivatel odloguje (odpoji se od
terminalu), program provede prazdny prikaz '' a pokracuje dal. Normalne by byl take ukoncen!
(Pozn: stejneho efektu lze dosahnout lepe pomoci nohup
.
Funkce
- funkce se vykonavaji v ramci aktualniho shellu
- obvykle se deklaruji v souboru
.profile
, nebo je mozne je zadavat primo z prikazoveho radku. Zruseni deklarace funkce lze provest pomoci prikazuunset
. Po odhlaseni se z shellu deklarace funkce zanika. -
chceme-li, aby funkce vracela hodnotu, ktera signalizuje, jakym zpusobem
probehlo vykonani prikazu, pouzije se prikaz
return
. Prikazexit
by totiz ukoncil nejen funkci, ale i shell, protoze funkce se vykonava v aktualnim shellu.
SYNOPSIS
jmeno_funkce() { prikazy [return n] }
EXAMPLES
{
Dnesni datum a cas: `date`
return 0; # funkce skoncila s uspechem
}
$ datum && echo 'ok'
Dnesni datum a cas: So čen 29 15:35:34 CEST 2013
ok
$ unset datum
Funkci lze předávat argumenty obdobně, jako shellu:
while test $# -ne 0
do
echo $1
shift
done
}
$ testArgumentu raz dva tri
raz
dva
tri