Ří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:

for i in *.txt
do
    echo $i
    cat $i
done

Jinak zapsáno totéž:

$ for i in *.txt;do echo $i; cat $i; done

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:

#!/usr/bin/env bash

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:

$ B=1
$ 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.

until test -f data
do
    sleep 300
done

Srovnání příkazů while a until:

while test $# -ne 0     until test $# -eq 0
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

#!/usr/bin/env bash
if (test $# = 0)        # zavorky jsou zde pouzity jen pro vetsi nazornost
then
    echo Musite zadat aspon jeden argument
    exit 1
fi
echo Konec scriptu
#!/usr/bin/env bash
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ř:

$ (sort bigfile > temp && mv temp bigfile) || rm temp

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

#!/usr/bin/env bash
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:

while :
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é!)

if test "s1" != "s2"; then     
# 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=1
$ 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.

$ expr 21 + 9 '*' 2 / 6
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

Příkaz expr vyraz lze nahradit konstrukcí $((vyraz)), která se vyhodnotí mnohem rychleji. (Nemusí se používat obrácené apostrofy).
$ x=`expr $x + 1`
$ 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

$ trap "echo PROGRAM PRERUSEN;" 2
$ 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).

$ (trap '' 1; while :; do echo "Bezim v procesu $$"; sleep 5; done) &

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 prikazu unset. 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. Prikaz exit by totiz ukoncil nejen funkci, ale i shell, protoze funkce se vykonava v aktualnim shellu.

SYNOPSIS

jmeno_funkce() 
{
    prikazy
    [return n]
}

EXAMPLES

$ datum()
{
    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:

$ testArgumentu() {
    while test $# -ne 0
    do
        echo $1
        shift
    done
}
$ testArgumentu raz dva tri
raz
dva
tri
Komentář Hlášení chyby
Created: 13.7.2013
Last updated: 13.7.2013
Tato stánka používá ke svému běhu cookies, díky kterým je možné monitorovat, co tu provádíte (ne že bych to bez cookies nezvládl). Také vás tu bude špehovat google analytics. Jestli si myslíte, že je to problém, vypněte si cookies ve vašem prohlížeči, nebo odejděte a už se nevracejte :-). Prohlížením tohoto webu souhlasíte s používáním cookies. Dozvědět se více..