2. První program
Náš první program nemůe být samozřejmě nic jiného ne naprosto klasické "Hello World" :-) Tento program jednoduše vypíše na obrazovku slova Hello World. Take nyní nastartujem textový editor a napíšeme do něj následující řádky:
#!/bin/bash
echo "Hello, world"
První řádka programu říká Linuxu, co se má pouít za interpret. V našem případě tedy bash, který se nachází v /bin/bash. Jestlie však je váš bash v jiném adresáři, musíte zadat jinou cestu. Určení interpretru, který bude program vykonávat je velice důleité, protoe pak by se taky mohlo stát, e skript bude vykonávat úplně jiný interpretr a tam by náš skript pravděpodobně vůbec běet nemusel. Příkaz echo provede výstup zadaného řetězce na obrazovku. Pro bliší prozkoumání některých příkazů lze pouít manuálových stránek. Teđ u zbývá pouze tento skript spustit. Implicitně textový editor nedá souboru právo spuštění. Musíme ho tedy dodat explicitně příkazem chmod. Předpokládejme, e se náš skript jmenuje hello.sh (přípona sh není podmínkou, většina skriptů ádnou příponu nemá). Pak bude zápis chmod vypadat takto:
xconsole$ chmod 700 ./hello.sh
xconsole$ chmod +x ./hello.sh
Následně skript můeme spustit takto:
xconsole$ ./hello.sh
Hello, world
A je to! Máte první program. A funguje. Sice zatím toho mnoho neumí, ale jako demonstrace primitivního programu zatím postačí. Take čeho jsme docílili? Pouili jsme příkaz shellu echo, který zajistil výpis textu na obrazovku. Jeho paramtrem je právě ten text. Je také moný ještě volitelný parametr -n, který zajistí to, e po vypsání textu neskočí na další řádku. A ještě zkuste jednu věc. Napište přímo do příkazové řádky toto:
xconsole$ echo "Hello, world"
Hello, world
Je tedy doufám zřejmé, které příkazy se pouívají v bash skriptu. Ty stejné, co můete napsat přímo do příkazové řádky.
Nyní tedy zkusme napsat mnohem uitečnější program. Program, který přesune všechny soubory do adresáře, a pak tento adresář smae i s tím, co obsahuje. Poté se tento adresář znovu vytvoří. To můeme udělat následujícími příkazy:
xconsole$ mkdir trash
xconsole$ mv * trash
xconsole$ rm -rf trash
xconsole$ mkdir trash
Místo toho, aby jsme to pořád psali do příkazové řádky, můeme si na to místo toho vyvořit na tuto úlohu skript:
#!/bin/bash
mkdir trash
mv * trash
rm -rf trash
mkdir trash
echo "Všechny soubory jsou smazány!"
Tento soubor můeme nazvat třeba clean.sh, nastavit práva a pouívat. Jednoduché, e? Do programu je také moné přidat komentář. Děje se tak pomocí znaku #. Začíná-li řádka právě tímto znakem, bere se tato řádka jako poznámka. Tedy tato řádka se nevykonává. Jedinou výjimku tvoří právě první řádka skriptu, ve které je uveden interpreter, který provede skript. Je dobré poznámky pouívat u jen z toho důvodu, aby jste si program zpřehlednili. (I kdy správný programátor ví, e komentáře jsou zbytečné, e činnost programu vyplyne z kódu.) Ještě bych upozornil na vyuívání manuálových stránek (nebo na nápovědu info). Mnoho variant pouití konkrétního příkazu se dozvíte právě zde. Pro ukázku bych vám zde uvedl manuálovou stránku programu echo:
JMÉNO
echo - zobrazí řádek textu
POUŽITÍ
echo [-ne] [řetězec ...]
echo {--help,--version}
POPIS
Tato manuálová stránka popisuje GNU verzi příkazu echo.
Pamatujte, e většina shellů má vestavěný příkaz stejného
jména s podobnou funkcí.
Příkaz echo vypíše všechny zadané řetězce na standardní
výstup, oddělené mezerami a ukončené znakem newline.
VOLBY
-n Nevypisovat závěrečný znak newline.
-e Povolit interpretaci následujících obráceným
lomítkem uvozených znaků v řetězcích:
\a pípnutí, zvonek (bell)
\b backspace
\c nevypisovat závěrečný znak newline
\f nová stránka (form feed)
\n nový řádek (new line)
\r návrat vozíku (carriage return)
\t horizontální tabelátor (horizontal tab)
\v vertikální tabelátor (vertical tab)
\\ obrácené lomítko (backslash)
\nnn znak, jeho ASCII kód je nnn (osmičkově)
VOLBY
Kdy je GNU příkaz echo vyvolán právě s jedním parametrem, jsou rozpoznávány následující volby:
--help Vypíše návod k pouití na standardní výstup a bezchybně skončí.
--version
Vypíše číslo verze na standardní výstup a bezchybně skončí.
3. Proměnné
Proměnné jsou vlastně takové "krabičky" do kterých se ukládají hodnoty (laicky řečeno). Jsou to tedy místa v paměti označená identifikátorem (názvem proměnné). Tento identifikátor představuje pro překladač/interpreter adresu místa v paměti, kde je uloena hodnota odpovídající proměnné. Samozřejmě hodnoty proměnných lze měnit. V bash se proměnné deklarují např takto:
#!/bin/bash
x=5 echo "Hodnota proměnné x je $x."
Z příkladu je tedy dobře vidět, e proměnné se deklarují tím, e se jim přiřadí nějaká hodnota. Je to tedy obdobné jako v BASICu. Další řádka programu vytiskne na obrazovku (tedy pokud nepřesměrujeme výstup :-) větu Hodnota proměnné x je 5. Z příkladu je té patrno, e k proměnné se přistupuje pomocí znaku symbolu dolaru ($) uvedeného před názvem proměnné. A ještě něco pro ty, kteří rádi mezery mezi =. V bash nesmí být u rovná se mezera! Proměnná x by se toti brala jako příkaz a rovná se její parametr. Vzhledem k tomu, e příkaz x neexistuje, ohlásil by bash chybu. Pouívá se tedy zápis:
jméno_proměnné=hodnota_proměnné
Co se proměnných týče, obecně jsou v bash dva typy proměnných. Lokálních (platných pouze pro konkrétní spuštěný skript) a systémových (platných pro celý operační systém, které lze vyuít všemi programy v systému). Pokud by jste chtěli svou proměnnou udělat jako systémovou, musíte pouít tento způsob deklarace:
#!/bin/bash
export x=5
nebo také
#!/bin/bash
x=5
export $x
Systémové proměnné se dají také vyuít. Například pro zjištění názvu interpretru, který je právě spuštěný:
xconsole$ echo $SHELL
/bin/bash
Systémové proměnné jsou většinou definovány v /etc/profile a v ~/.bash_profile. Příkaz echo je dobrý právě ke zjišování těchto proměnných. Chtěli-li by jste vypsat seznam všech systémových proměnných v systému, existuje příkaz env, který tyto proměnné vypíše.
4. Řídící struktury
Řídící struktury můou váš program řídit a tím ho udělat mnohem více uitečný a efektivnější. Velmi důleitá je například detekce chyb. Příklad programu s řídící strukturou by mohl být tento:
#!/bin/bash
cp /etc/foo .
echo "Hotovo!"
Tento skript nazvěme například bar.sh. Jeho činnost spočívá v tom, e zkopíruje soubor /etc/foo do aktivního adresáře a nakonec vypíše "Hotovo!". Ale uvědomte si, e ne kadý má ve svém adresáři soubor /etc/foo. V tom případě se ádný soubor nezkopíruje, program cp vypíše chybu a poté se v klidu vypíše "Hotovo!". Toto chování by se však nemělo objevovat. V pseudokódu by to tedy mělo vypadat takto:
jestli /etc/foo existuje pak
kopíruj /etc/foo do aktivního adresáře
napiš na obrazovku "Hotovo!"
jinak
napiš na obrazovku "Soubor neexistuje!" konec
Mohlo by toto být realizováno v bash? Samozřejmě! Jeho řídící strkutury jsou: if, while, until, for a case. Kadá tato struktura je tzv. párová. To znamená, e začíná jako "návěst" a končí taky "návěst". Například struktura podmínky začíná if a končí fi. Řídící struktury nejsou programy, které by jste mohli nalézt v systému. Jsou to pouze interní funkce shellu bash. Řídící struktury obecně tvoří základ tazvaného strukturovaného programování.
Řídící struktury, které bash podporuje:
4.1 If ... else ... elif ... fi
4.2 While ... do ... done
4.3 Until ... do ... done
4.4 For ... in ... do ... done
4.5 Case ... in ... esac
4.1 If ... else ... elif ... fi
Jedna z nejběnějších a nejdůleitějších struktur ve skriptech je právě struktura if. Ta umoňuje na základě podmínky vykonat buđ tu nebo jinou činnost. Pouívá se na větvení programu, kde na základě vyhodnocení podmínky se pokračuje danou částí kódu. Příklad struktury if je zde:
if test -f /etc/foo
then #Soubor existuje. Zkopíruj tedy soubor
cp /etc/foo .
echo "Hotovo!"
else
# Soubor neexistuje. Vypiš tedy chybu
echo "Soubor neexistuje!"
exit
fi
Tento příklad tedy na základě vyhodnocení příkazem test soubor /etc/foo zkopíruje nebo neexistuje-li soubor, vypíše se chybové hlášení. K otestování existence souboru je pouit příkaz test. Příkaz na základě přepínače -f určí, zda-li je /etc/foo soubor. Další monosti přepínače příkazu test shrnuje následující tabulka. Je také mono pouít manuálovou stránku.
-d testuje, jestli soubor je adresář
-e testuje, jestli soubor existuje
-f testuje, jedná-li se o regulární soubor
-g testuje, má-li soubor povolení SIGD
-r testuje, zda-li jde soubor číst
-s testuje, zda-li velikost souboru není 0
-u testuje, má-li soubor povolení SUID
-w testuje, zda-li se dá do souboru zapisovat
-x testuje, zda-li je soubor spustitelný
Jestlie není splněna podmínka testovaná příkazem if, neprovede se tedy blok příkazů uvedený za slovem then, ale za to se provedou příkazy v bloku zahájeném příkazem else (pokdu se vyskytuje). Je zde také slovo elif. To je pouíváno pro testování podmínky místo příkazu else. Normálně se toti blok příkazů začínající else provede automaticky po nesplnění podmínky. Ale příkaz elif místo příkazu else umoní, e se tento blok provede jen pokud vyhoví podmínka za příkazem elif.
Připadá-li vám formát podmínky příliš nekomfortní, je moné pouívat také formát následující:
if test -f /etc/foo
then
# se dá také zapsat takto:
if [ -f /etc/foo ]; then
Hranaté závorky nahrazují příkaz test. Máte-li zkušenosti s programováním v jazyce C, můe vám tato syntaxe připadat více komfortnější. Středník ; říká interpretru, e je zde konec řádku. Všechno, co následuje za středníkem je chápáno jako by bylo na novém řádku. Je to důleité, protoe bash očekává příkaz then a na následujícím řádku.
4.2 While ... do ... done
Struktura while je struktura cyklu. V podstatě vykonává blok příkazů tak dlouho, dokud je splněna podmínka uvedena za slovem while. Příklad struktury while je zde:
#!/bin/bash
while true; do
echo "Press Ctrl-C to quit."
done
Příkaz true je program, který vdy vrací hodnotu true (pravda). Náš skript tedy bude neustále opakovat vypisování hlášky jak ukončit program a to a do té doby ne ho uměle přerušíme (Ctrl-C). Způsob volání true je však poněkud pomalý, protoe systém musí vdy spouštět program true. Existuje rychlejší varianta jak docílit toho samého příkladu jak před tím a to pouítím dvojtečky místo true:
#!/bin/bash
while :; do
echo "Press Ctrl-C to quit."
done
Dvojtečka je toti interní příkaz interpretru bash. Tento příklad je však poněkud nepraktický, tak pojđme na další u více uitečný.
V následujícím příkladu pouijeme proměnnou x, která bude při kadém průchodu cyklu zvyšovat svojí hodnotu a to a do té doby ne dosáhne hodnoty 10.
#!/bin/bash
x=0; # inicializuje hodnotu x na 0
while [ "$x" -le 10 ]; do
echo "Aktuální hodnota x: $x"
# zvýšení hodnoty x o 1
x=$(expr $x + 1)
sleep 1
done
Jak vidíte, pouíváme příkaz test (hranaté závorky), abychom zjistili, jestli hodnota proměnné x je menší nebo rovno 10. Je-li menší nebo rovno 10, test je vyhodnoceno jako true a blok příkazů za slovem do se můe provést. Je-li však podmínka vyhodnocena jako false, pokračuje program v běhu za slovem done.
Následující tabulka shrnuje další monosti příkazu test.
x -eq y Testuje, jestli x=y
x -ne y Testuje, jestli x!=y (nerovná se)
x -qt y Testuje, jestli x>y
x -lt y Testuje, jestli x<y
Pro řetězce:
x = y Testuje, jsou-li řetězce shodné
x != y Testuje, jsou-li řetězce rozdílné
-n x Vrátí true, není-li řetězec prázdný
-z x Vrátí true, je-li řetězec prázdný
Věřím, e nebude těké porozumět i dalšímu příkazu ve skriptu a to je expr. Tento příkaz ve skriptu přičte k proměnné x hodnotu 1 a vrátí to do x. Ale co znamená $(...)? Tato konstrukce zařídí, e hodnota výsledeku výrazu v závorkách se zapíše jako hodnota do výrazu, který tuto konstrukci obsahuje. Je tedy moné tímto způsobem například zjistit pod jakým jménem jsme přihlášeni do systému. Příklad:
#!/bin/bash
x=$(whoami)
echo "Já jsem $x."
Samozřejmě lze také tímto způsobem dostat hodnotu vrácenou příkazem whoami přímo do řetězce. A to takto:
#!/bin/bash
echo "Já jsem $(whoami)."
Můete se rozhodnout, který způsob je pro vás lepší. Konstrukce $(...) nám tedy dává opět další prostředek jak spustit příkaz a ještě pouít hodnotu, kterou příkaz vrátí.
4.3 Until ... do ... done
Struktura until je velice podobná struktuře while. Jediný rozdíl je ve vyhodnocování podmínky pro běh bloku kódu mezi slovy do a done. Ve struktuře until se blok kódu provede pouze, je-li podmínka vyhodnocena jako false (nepravda). Zde je příklad struktury:
#!/bin/bash
x=0
until [ "$x" -ge 10 ]; then
echo "Aktuální hodnota x: $x"
x=$(expr $x + 1)
sleep 1
done
Tento kód vypadá velice podobně kódu příkladu uvedeného v předchozí kapitole. Vlastně se liší jen ve dvou věcech. Je pouita struktura until a tedy příkaz test je upraven tak, aby byla struktura ukončena bude-li hodnota proměnné x větší nebo rovno 10. Znamená to tedy, e se vypíší hodnoty pouze od 0 do 9.
Příkaz sleep pozastaví běh skriptu na tolik sekund, kolik je uveden parametr (v našem případě pozastaví běh skriptu na 1 sekundu). Další monosti příkazu sleep se můete dozvědět v manuálových stránkách, které říkají o příkazu sleep následující:
JMÉNO
sleep - čeká zadaný časový interval
POUŽITÍ
sleep [--help] [--version] číslo[smhd]...
POPIS
Tato manuálová stránka popisuje GNU verzi příkazu sleep.
Příkaz sleep čeká časový interval, který je součtem hodnot zadaných parametry. Kadý argument je číslo nepovinně
následované označením jednotky. Implicitní jednotkou jsou sekundy. Povolené jednotky jsou:
s sekundy
m minuty
h hodiny
d dny
VOLBY
--help Vypíše návod k pouití na standardní výstup a bezchybně skončí.
--version
Vypíše číslo verze na standardní výstup a bezchybně skončí.
4.4 For ... in ... do ... done
Struktura for se pouívá, chcete-li během cyklu pouít různé hodnoty pro jednu proměnnou, a to tak, e při kadém průběhu cyklu bude mít proměnná jinou hodnotu. Například chcete napsat skript, který desetkrát vytiskne kadou sekundu tečku (.) lze to provést takto:
#!/bin/bash
echo -n "Zjišuji chyby v systému"
for dots in 1 2 3 4 5 6 7 8 9 10; do
echo -n "."
echo "Systém je čistý."
done
V příkazu echo vidíme parametr -n. Tento parametr určuje, e po vypsání textu se neskočí na další řádku na obrazovce, ale bude se pokračovat přímo za vypsaný text. Pro lepší pochopení zkuste jednou tento skript bez -n a jednou s -n. Rozdíl jasně uvidíte.
Nyní zpět k příkazu for. Za příkazem forse uvede název proměnné, která bude měnit svou hodnotu podle hodnot uvedených za slovem in. Blok příkazů, který se bude s takovouto hodnotou provádět je ohraničen klíčovými slovy doa done. V našem případě tedy bude proměnná x postupně nabývat hodnot 1 a 10 při kadém jednotlivém průběhu cyklu. Tyto hodnoty však v našem cyklu nejsou pouity (ale samozřejmě pouity být můou, a běne se tak děje). V našem konkrétním případě slouí pouze pro to, aby cyklus proběhl desetkrát. Nyní si tedy uvedeme další příklad ve kterém u budou hodnoty v cyklu pouity:
#!/bin/bash
echo "Zjišuje se existence adresářů v systému"
for x in /dev /etc /bin /root /var /usr /home /mnt; do
if [ -d "$x" ]; then
echo "Adresář $x existuje"
else
echo "Adresář $x neexistuje"
fi
done
Tento příklad testuje postupně jestli existují některé vybrané adresáře v systému uvedené jako hodnoty ve struktuře for. V příkladu je zkombinována struktura for se strukturou if. Je zde moné vidět, e jednotlivé řídící struktury lze vnořovat do sebe. Zde je také vidět, e jako hodnoty pro for můou být té pouity řetězce. Další uitečný příklad ukáe, jak je moné přidat všem souborům v aktuálním adresáři příponu html. Ukáe, e je tedy moné pouít i olíkové znaky pro výběr souborů (v našem případě všechny soubory, tedy *):
#!/bin/bash
for file in *; do
echo "Přidávám příponu .html souboru $file..."
mv $file $file.html
done
Žolíkové znaky tvoří obecně silnou stránku shellu a také jeho pouívání a programování značně usnadňují a přidávají mu velkou sílu a výkonnost.
4.5 Case ... in ... esac
Struktura case je velmi podobná struktuře if. V základu struktura case je určena pro vykonání jednoho z několika kusů kódu a to podle toho, jakou hodnotu má proměnná uvedená za příkazem case. Zde je příklad struktury case:
#!/bin/bash
x=5; # inicializuje x na hodnotu 5
# nyní se bude testovat hodnota x:
case $x in
0) echo "Hodnota x je 0."
;;
5) echo "Hodnota x je 5."
;;
9) echo "Hodnota x je 9."
;;
*) echo "Hodnta x není ani 0, ani 5, ani 9."
esac
Je tedy vidět, e se vykoná příkaz, který je zapsán u hodnoty 5, kterou proměnná x má. Nastane-li situace, e proměnná x nebude ani 0, 5 nebo 9, provede se příkaz určen znakem *. Příkaz case tedy vyhodnotí hodnotu řídící proměnné x, podle hodnoty se poté najde příslušná hodnota před závorkou a ta se provede. Nebude-li odpovídat ádné hodnotě ve struktuře, zkusí se nalést *) a provede se blok příkazů za ním. Nenalezne-li se hvězdička, ádný příkaz ve struktuře se neprovede. Celá konstrukce by se té dala realizovat strukturou if:
#!/bin/bash
x=5
if [ "$x" -eq 0 ]; then
echo "Hodnota x je 0."
elif [ "$x" -eq 5 ]; then
echo "Hodota x je 5."
elif [ "$x" -eq 9 ]; then
echo Hodnota x je 9.
else
echo "Hodnota x je neurčena."
fi
Práce struktury case je tedy podle známé struktury if patrná. Nakonec ještě jeden příklad speciální konstrukce pomocí case.
#!/bin/bash
echo "Je nyní ráno? Odpovězte \"ano\" nebo \"ne\""
read timeofday
case "$timeofday" in
ano | a | Ano | ANO )
echo "Dobré ráno"
;;
[nN]* )
echo "Dobré odpoledne"
;;
* )
echo "Promiňte, ale nerozuměl jsem"
echo "Odpovězte \"ano\" nebo \"ne\""
exit 1
;;
esac
exit 0
Pro ještě lepší a efektivnější kontrolu odpovědi ano můeme vyuít kontrukce pomocí olíkových znaků
[aA] | [aA][nN][oO] )
5. Uvozovky
V shellu bash můete psát tři různé typy uvozovek, z nich kadé mají jiný význam. A to jednak dvojité uvozovky: ", přední uvozovka: ' (tzv. devítka nebo apostrofa), a zadní uvozovka: `.
Dvojitá uvozovka se pouívá hlavně k určení několika slov oddělenými mezerami jako jeden řetězec. Tedy slova ve dvojitých uvozovkách se povaují vdy za jeden parametr, a to jako jeden řetězec. Například pouijeme-li příkaz:
xconsole$ mkdir hello world
xconsole$ ls -F
hello/ world/
Uvidíme to, co po pouití příkazu ls -F vidíme. To jest vytvořené dva samostatné adresáře. Ale pokud pouijeme následně jako parametr "hello world", uvidíme toto:
xconsole$ mkdir "hello world"
xconsole$ ls -F
hello world/
Vidíme tedy, e chceme-li vytvořit adresář, který obsahuje dvě a více slov oddělenými mezerami, musíme tento název uvést v dvojitých uvozovkách, jinak se nám vytvoří adresářů několik, z nich kadý bude mít název jako jedno ze slov uvedeného jako parametr příkazu mkdir.
Přední uvozovky také uzavírají řetězec podobně jako dvojté uvozovky, ale je zde jeden rozdíl. Řetězec uzavírající přední uvozovky bude zobrazen přesně tak, jak je zadán. Lepší pochopení usnadní následující příklad:
#!/bin/bash
x=5
echo "Hodnota proměnné x je $x"
echo 'Hodnota proměnné x je $x'
Pro pochopení je vhodné skript spustit a prohlédnout si výsledek. Je z toho patrné, e při pouití dvojitých uvozovek se provede nahrazení $x za konkrétní hodnotu, kdeto pokud je výraz uzavřen do předních uvozovek (apostrof), k tomuto nahrazení nedojde.
Poslední typ uvozovek (zadní uvozovky) se pouívá místo této konstrukce:
x=$(expr $x + 1)
Jak vidíte x je přiřazena hodnota o jedno větší ne byla hodnota x před provedením. Proměnná x se tedy inkrementovala. Zápis lze také provést pomocí uvozovek:
x=`expr $x + 1`
Který způsob je lepší? To záleí na vás. Já mám raději $(...), ale jak říkám, záleí na vás, jaký způsob vám lépe vyhovuje. Pouít lze obojí. I kdy, někdy je moná estetičtější, obzvláště v řetězcích, pouít výraz se závorkami:
echo "Já jsem `whoami`."
6. Aritmetika v BASH
BASH také podobně jako většina programovacích jazyků dovede provádět matematické výrazy. Jak jste ji viděli, aritmetika se provádí pomocí příkazu expr. Nicméně stejně jako příkaz true je i příkaz expr pomalý, a proto lze aritmetika dělat pomocí interních příkazů bash. Stejně jako je dvojtečka alternativa k příkazu true, je i k příkazu expr alternativa. A tou je uzavření výrazu do kulatých závorek. Výsledek tedy dostaneme pomocí konstrukce $((...)). Rozdíl oproti výrazu $(...) je v počtu závorek.
Zkuste tedy následující příklad:
#!/bin/bash
x=8
y=4
z=$(($x + $y))
echo "Součet $x a $y je $z"
Bash je schopen vykonat i následující matematické operace:
sčítání + odčítání - násobení * dělení / dělení modulo %
Dělení modulo je zbytek po dělení. Tedy například 5 % 2 = 1, protoe 5 děleno 2 je 2, zbytek 1. Je také nutno podotknout, e bash dovede pracovat pouze s čísly celými. Nelze tedy pouívat desetinná čísla.
Zde je příklad skriptu s aritmetickými operacemi:
#!/bin/bash
x=5
y=3
add=$(($x + $y))
sub=$(($x - $y))
mul=$(($x * $y))
div=$(($x / $y))
mod=$(($x % $y))
echo "Součet: $add"
echo "Rozdíl: $sub"
echo "Součin: $mul"
echo "Podíl: $div"
echo "Zbytek: $mod"
Místo add=$(($x + $y)) je té moné pouít add=$(expr $x + $y) nebo add=`expr $x + $y`.
Manuálová stránka příkazu expr je uvedena zde.
JMÉNO
expr - vyhodnotí výraz
POUŽITÍ
expr výraz...
expr {--help,--version}
POPIS
Tato dokumentace není dále udrována a můe být nepřesná nebo neúplná. Autoritativním zdrojem je Texinfo dokumentace.
Tato manuálová stránka popisuje GNU verzi příkazu expr. Příkaz expr vyhodnotí výraz a vypíše výsledek na standardní výstup. Kadé slovo (token) ve výrazu musí být zadáno jako samostatný parametr. Operandy ve výrazech jsou buď čísla nebo řetězce. Psaní řetězců do uvozovek nebo apostrofů příkaz expr sám nevyaduje, ale jejich pouití můe být nezbytné, aby speciální znaky v řetězcích neinterpretoval shell. Příkaz expr automaticky převádí operandy ve výrazech na celá čísla nebo řetězce podle toho, jaké na ně mají být aplikovány operace.
Příkaz expr rozpoznává následující binární operátory (zde seřazené od nejniší po nejvyšší prioritu):
| Pokud první argument není ani prázdný řetězec (null) ani 0, je výsledkem první argument, jinak je výsledkem druhý argument. Obvykle se pouívá jako logické `nebo'.
& Jestlie ani jeden argument není ani prázdný řetězec (null) ani 0, je výsledkem první argument, jinak je výsledkem 0.
< <= = == != >= > Pokusí se převést oba argumenty na čísla a provést číselné porovnání; jestlie převod na čísla není moné uskutečnit, provede abecední porovnání. Vrátí 1, jestlie je podmínka porovnání splněna, jinak vrátí 0. Operátor == je synonymem pro =.
+ - Arit. operace sčítání a odčítání. Oba argumenty jsou napřed převedeny na čísla; je chybou, jestlie není moné převod na čísla provést.
* / % Arit. operace násobení, dělení a zbytek po celočíselném dělení, jako v jazyku C. Oba argumenty jsou napřed převedeny na čísla; je chybou, jestlie není moné převod na čísla provést.
: Porovnání řetězce s regulární výrazem. Oba argumenty jsou převedeny na řetězce a na začátek druhého je automaticky přidán znak `^'. Potom je první argument porovnán s druhým, který je interpretován jako regulární výraz. Pokud první řetězec vyhovuje regulárnímu výrazu, pak je porovnání úspěšné. V tomto případě, jestlie je část druhého operandu uzavřena mezi `\(' a `\)', bude výsledkem ta část prvního řetězce, která vyhovovala části regulárního výrazu mezi `\(' a `\)', jinak je výsledkem číslo udávající, kolik znaků prvního řetězce vyhovovalo celému regulárnímu výrazu. Pokud porovnání úspěšné nebylo, pak jestlie v regulárním výrazu bylo `\(' a `\)', je výsledkem prázdný řetězec, jinak je výsledkem 0. Můe být pouit nejvýše jeden pár `\(' a `\)'.
Navíc jsou rozpoznávána následující klíčová slova:
match řetězec regex
Alternativní zápis porovnání s regulárním výrazem. Toté jako ``řetězec : regex''.
substr řetězec pozice délka
Vrátí podřetězec zadaného řetězce začínající na zadané pozici a nejvýše o zadané délce. Jestlie pozice a délka nejsou kladná čísla, vrátí prázdný řetězec.
index řetězec seznam-znaků
Vrátí první pozici v řetězci, na které je některý ze znaků uvedených v seznamu-znaků. Jestlie v řetězci není ádný znak ze seznamu-znaků, vrátí 0.
length řetězec
Vrátí délku řetězce. Pro vyznačení pořadí vyčíslování je moné pouít kulaté závorky. Klíčová slova nemohou být pouita jako řetězce.
VOLBY
Kdy je GNU příkaz expr vyvolán právě s jedním parametrem, jsou rozpoznávány následující volby:
--help Vypíše návod k pouití na standardní výstup a bezchybně skončí.
--version Vypíše číslo verze na standardní výstup a bezchybně skončí.
PŘÍKLADY
Přičtení jedničky do proměnné shellu a: a=`expr $a + 1`
Následující příklad můe být pouit pro vypsání poslední sloky jména souboru uloeného v proměnné a (hodnota v a nemusí obsahovat `/'):
expr $a : '.*/\(.*\)' \| $a
-- metaznaky shellu je nutné dávat do uvozovek či apostrofů.
Příkaz expr nastavuje následující kódy ukončení (exit status):
0 jestlie výsledek není ani prázdný řetězec ani 0,
1 jestlie výsledek je prázdný řetězec nebo 0,
2 pro chybné výrazy.
7. Čtení uivatelského vstupu
Nyní konečně přichází nějaká zábavná část. V bashi můete vytvořit program, který bude interaktivní, tedy reagovat na vstup uivatele (popř. na vstup čtený ze souboru). Příkaz uivatelského vstupu je příkaz read. Jedná se o vnitřní příkaz shellu. Příkaz vyaduje jako parametr proměnnou. Nyní si uveđme jednoduchý příkald:
#!/bin/bash
echo -n "Zadej své jméno: "
read jmeno
echo "Zdravím tě $jmeno!"
Skript počká, a napíšete vaše jméno a zmáčknete klávesu ENTER. Pak se to, co jste napsali uloí jako hodnota do proměnné jmeno. Ta se pak můe dále v programu vyuívat stejně jako jakoukoliv jinou proměnnou. Vyuití hodnoty zadané uvádí následující příklad:
#!/bin/bash
echo -n "Zadej své jméno: "
read jmeno
if [ -z "$jmeno" ]; then
echo "Tys mi neřek tvé jméno!"
exit
fi
echo "Zdravím tě $jmeno!"
Toto je typický příklad kontroly vstupních dat. Nemůeme toti předpokládat, e uivatel vdy zadá to, co očekáváme a je tedy nutné se proti tomu bránit. Je však vhodné uivatele na špatně zadané data upozorňovat citlivě a ne tak, aby si uivatel z toho vydedukoval, e si o něm myslíme, e je blbec. Jestlie uivatel nezadá ádné jméno, bude podmínka vyhodnocena jako true, vypíše se chybové hlášení a skript se ukončí.
8. Funkce
Funkce dělají skriptování mnohem jednodušší a překlednější. Rozdělují toti program do jednodušších menších kousků. Funkce provádí vámi definované příkazy a také můe vracet hodnotu. Funkce můete volat z hlavního programu. Doteď jsme toti psali všechno do hlavního programu. Funkce umoňují dílčí úkoly rozloit do menších částí kódu, které lze volat v programu, a to i vícekrát. Před pokračováním si uvedeme příklad funkce, která pouze vypíše text:
#!/bin/bash
hello()
{
echo "Nyní jsme ve funkci hello()"
}
echo "Nyní se zavolá funkce hello()..."
hello
echo "Nyní jsme zase mimo funkci hello()"
Nyní se na funkci podíváme blíe. Funkce zde v našem konkrétním případě plní účel vypsání textu, který nás pouze informuje o tom, e je funkce prováděna. Funkce samozřejmě můe dělat mnohem komplikovanější úlohy, ale právě zde jen vytiskne text. Funkci vdy voláme napsáním jejího jména do programu, její jméno můe být libovolné. V našem programu se jmenuje hello, a volá se:
hello
Kdy je tento řádek vykonáván, bash prohledá skript, zdali je v něm funkce hello(). Nalezne-li jí, tak provede příkazy, které jsou v ní zapsány.
Samotná funkce je určena svým názvem po kterém následuje dvojice kulatých závorek (). Blok příkazů ve funkci je uzavřen sloenými závorkami {...}. Ty značí začátek a konec funkce. Veškerý kód funkce bude vykonán pouze, bude-li funkce zavolána. Funkce by také měla být vdy definována ještě před tím, ne bude zavolána. Je té přípustné, e před názvem funkce můe být slovo function. Funkce tedy vypadá takto:
hello()
{
echo "Nyní jsme ve funkci hello()"
}
Nebo další moný zápis je:
function hello()
{
echo "Nyní jsme ve funkci hello()"
}
Jak to tedy funguje?
Skript se začne normálně provádět od začátku, jak jsme zvyklí, take nic nového. Kdy ale narazí na konstrukci [ 'function' ] hello (), ví, e se jedná o definici funkce jménem hello. Zapamatuje si, e hello odkazuje na funkci a pokračuje v provádění příkazů po odpovídající sloené závorce. Jakmile narazí na řádek foo, vi, e má provést dříve definovanou funkci. Po skončení funkce se pokračuje na řádku, který následuje po volání funkce foo.
Dříve ne funkci vyvoláte, ji vdy musíte nejprve definovat, podobně jako v jazyce Pascal, jen s tou výjimkou, e v shellu neexistuje ádná deklarace forward. To ale nebývá problém, protoe se všechny skripty provádějí od začátku, take pokud umístíte všechny funkce před první volání libovolné funkce, budou vdy všechny funkce před prvním volání definovány.
Při volání funkce jsou poziční parametry skriptu $*, $@, $#, $1, $2 atd. nahrazeny parametry funkce. Pomocí nich pak čtete parametry předané funkci. Po skončení funkce jsou hodnoty všech parametrů zase obnoveny. Tyto parametry se pouívají stejně jako proměnné.
Funkce mohou pomocí příkazu return vracet číselnou hodnotu. Pokud je potřeba vrátit řetězec, uloí se do proměnné, kterou lze po skončení funkce pouít. Případně můete řetězec vypsat příkazem echo a výsledek odchytit jako v následujícím příkladu:
#!/bin/bash
foo()
{
echo Ahoj
}
…
result="$(hello)"
Uvnitř shellu můete za pomoci klíčového slova local deklarovat lokální proměnné. Proměnná pak existuje jen v rámci dané funkce. Jinak můe funkce přistupovat k jiným proměnným shellu, které jsou v podstatě globální. Pokud má lokální proměnná stejný název jako globální, pak tuto proměnnou potlačí, ale jen v rámci příslušné funkce. Abychom si to demonstrovali, ukáeme si následující příklad:
#!/bin/bash
vzorový_text="globální proměnná"
foo()
{
local vzorový_text="lokální proměnná"
echo "Provádí se funkce foo"
echo $vzorový_text
}
echo "Začátek skriptu"
echo $vzorový_text
foo
echo "Konec skriptu"
echo $vzorový_text
exit 0
Pokud funkce neobsahuje příkaz return, vrací návratový kód posledního provedeného příkazu.
V následujícím příkladu si ukáeme způsob předávání parametrů funkci a také způsob jakým mohou funkce vracet hodnoty true a false.
#!/bin/bash
yes_or_no() {
echo "Je tvé jméno $* ?"
while true
do
echo -n "Napiš ano nebo ne: "
read x
case "$x" in
a | ano ) return 0;;
n | ne ) return 1;;
* ) echo "Napiš ano nebo ne"
esac
done
}
echo "Původní parametr je $*"
if yes_or_no "$1"
then
echo "Ahoj $1, pěkné jméno"
else
echo "Nikdy"
fi
exit 0
Tento příklad funguje tak, e po spuštění skriptu je definována funkce yes_or_no, ale není provedena. V příkazu if provede skript funkci yes_or_no, které předá jako parametry zbytek řádku, kde zápis $1 nahradí prvním parametrem skriptu. Funkce pak pracuje s těmito parametry, které jsou nyní uloeny v pozičních proměnných $1, $2 atd. a vrátí hodnotu volajícímu příkazu. Příkaz if v závislosti na návratové hodnotě provede příslušní příkaz.
9. Zachytávání signálů
Signál je událost, kterou generuje systém UNIX (Linux) jako odpověď na nějakou podmínku a po jeho přijetí můe proces (skript) provést nějakou akci. Signály generují některé chybové podmínky, například porušení segmentů paměti, chyby procesoru v plovoucí čárce nebo neplatné instrukce. Jsou generovány shellem a ovladači terminálu, které vyvolají přerušení. Můe je také jeden proces explicitně poslat druhému procesu a předat mu tak nějakou informaci, případně ovlivnit jeho chování. Ve všech těchto případech je programové rozhraní stejné. Signály mohou být generovány, odchytávány anebo (některé přinejmenším) ignorovány. Názvy signálů jsou definovány v hlavičkovém souboru signal.h. Všechny začínají zkratkou "SIG". Výpis signálů systému Linux je uveden níe.
Ve vašich skriptech je moné pouít zabudovaný program trap, který dovede zachytávat signály ve vašem programu. Je to dobrá cesta, jak uhlazeně ukončit program. Například, máte-li spuštěný program, zmáčknutím kláves Ctrl-C pošlete aplikaci signál přerušení, který zlikviduje váš program. Příkaz trap můe zachytit signál a dát tak šanci programu v pokračování. Nebo se zeptá uivatele, jestli má skončit. trap pouívá následující syntaxi:
trap akce signál
Kde akce je to, co bude vykonáno při doručení signálu aplikaci. Signál je název signálu, který bude-li doručen, tak se vykoná příslušná akce. Signály, které můe aplikace dostat si můete nechat například vypsat pomocí příkazu trap -l. Pouíváte-li signály ve vašem skriptu, musíte vynechat první tři písmena jeho názvu (obvykle je to SIG). Například je-li signál SIGINT, bude do skriptu zapsáno pouze INT. Můete také místo názvů signálů pouívat jejich čísla. Například číselná hodnota SIGINT je 2. Nyní vyzkoušejte následující program:
#!/bin/bash
trap sorry INT
sorry()
{
echo "Sorry, to jsem nechtěl!"
sleep 3
}
for i in 10 9 8 7 6 5 4 3 2 1; do
echo "$i sekund do selhání systému."
sleep 1
done echo "Systém selhal!"
Nyní zkuste program spustit a zmáčknout Ctrl-C. To pošle skriptu signál SIGINT, který by měl přerušit program. Jeliko však signál bude zachycen a dojde ke zpracování funkce sorry(), která však program neukončí, take bude běet dál.
Chcete-li však, aby byl signál ignorován úplně, pouijte jako akci "''". Chcete-li pak někde v programu ji standardní zpracování signálu, pouijte jako akci "-". Například:
# dojde-li signál, spustí funkci sorry()
trap sorry INT
# resetuje akci (nastavuje standardní chování SIGINT)
trap - INT
#nastavuje signál tak, aby byl ignorován
trap '' INT
Seznam signálů, které můete v Linuxu pouít (manuálová stránka signal z sekce 7 manuálových stránek):
JMÉNO
signal - seznam signálů
POPIS
V Linuxu jsou podporovány níe uvedené signály. Čísla některých signálů jsou závislá na architektuře. Nejprve jsou uvedeny signály popsané v normě POSIX.1.
Signál Hodnota Akce Poznámka
--------------------------------------------------------------------------
SIGHUP 1 A "Hangup" - při zavěšení na řídícím terminálu
nebo ukončení řídícího procesu.
SIGINT 2 A "Interrupt" - přerušení z klávesnice.
SIGQUIT 3 A "Quit" - ukončení z klávesnice.
SIGILL 4 A "Illegal Instruction" - neplatná instrukce.
SIGABRT 6 C "Abort" - ukončení funkcí abort(3)
SIGFPE 8 C "Floating point exception" - přetečení
v pohyblivé řádové čárce.
SIGKILL 9 AEF "Kill" - signál pro nepodmíněné ukončení
procesu.
SIGSEGV 11 C Odkaz na nepřípustnou adresu v paměti.
SIGPIPE 13 A "Broken pipe" - pokus o zápis do roury,
kterou nemá ádný proces otevřenou pro čtení.
SIGALRM 14 A Signál od časovače, nastaveného funkcí
alarm(1)
SIGTERM 15 A "Termination" - signál ukončení
SIGUSR1 30,10,16 A Signál 1 definovaný uivatelem
SIGUSR2 31,12,17 A Signál 2 definovaný uivatelem
SIGCHLD 20,17,18 B Zastavení nebo ukončení dětského procesu
SIGCONT 19,18,25 Pokračování po zastavení
SIGSTOP 17,19,23 DEF Zastavení procesu
SIGTSTP 18,20,24 D Zastavení znakem "Stop" z terminálu
SIGTTIN 21,21,26 D čtení z terminálu v procesu běícím na pozadí
SIGTTOU 22,22,27 D zápis na terminál v procesu běícím na pozadí
Následují ostatní signály:
Signál Hodnota Akce Poznámka
--------------------------------------------------------------------------
SIGTRAP 5 CG Přerušení při ladění (trasování,breakpoint)
SIGIOT 6 CG IOT - synonymum signálu SIGABRT
SIGEMT 7,-,7 G
SIGBUS 10,7,10 AG "Bus error" - pokus o přístup mimo
mapovanou pamě
SIGSYS 12,-,12 G Nepřípustný parametr syst. volání (SVID)
SIGSTKFLT -,16,- AG Chyba zásobníku koprocesoru
SIGURG 16,23,21 BG Soket přijal data s příznakem Urgent
(4.2 BSD)
SIGIO 23,29,22 AG Lze pokračovat ve vstupu/výstupu (4.2 BSD)
SIGPOLL AG Synonymum SIGIO (Systém V)
SIGCLD -,-,18 G Synonymum SIGCHLD
SIGXCPU 24,24,30 AG Překročen limit času CPU (4.2 BSD)
SIGXFSZ 25,25,31 AG Překročen limit velikosti souboru (4.2 BSD)
SIGVTALRM 26,26,28 AG Virtuální časovač (4.2 BSD)
SIGPROF 27,27,29 AG Časovač pouívaný při profilování
SIGPWR 29,30,19 AG Výpadek napájení (Systém V)
SIGINFO 29,-,- G Synonymum SIGPWR
SIGLOST -,-,- AG Zámek souboru byl ztracen
SIGWINCH 28,28,20 BG Změna velikosti okna (4.3 BSD, Sun)
SIGUNUSED -,31,- AG Nepouívaný signál
(Znak - ve sloupci "Hodnota" znamená, e se signál na dané architektuře nepouívá. Jsou-li uvedeny tři hodnoty, první je obvykle pouita na procesorech Alpha a Sparc, druhá na i386 a PowerPC a poslední na procesorech MIPS. Výjimkou je signál č. 29, který na procesorech Alpha znamená SIGINFO / SIGPWE, ale na Sparcu SIGLOST.)
Příznaky ve sloupci "Akce" mají následující význam:
A Tento signál standardně ukončí proces.
B Tento signál je standardně ignorován.
C Tento signál standardně způsobí výpis paměti procesu (core dump).
D Tento signál standardně pozastaví provádění procesu.
E Tento signál nemůe být zachycen.
F Tento signál nemůe být ignorován.
G Tento signál není definován normou POSIX.1.
POZNÁMKA K PŘEKLADU
U často se vyskytujících signálů byly ponechány ve sloupci "Poznámka" i původní termíny. Snáze se pak z hlášení
shellu o ukončení procesu lokalizuje, kterým signálem byl proces přerušen.
SPLŇUJE STANDARDY
POSIX.1
CHYBY
Signály SIGIO a SIGLOST mají stejnou hodnotu. SIGLOST se ve zdrojových textech jádra ji nepouívá, ale při překladu určitých balíků software se stále předpokládá, e signál č.29 znamená SIGLOST.
DALŠÍ INFORMACE
kill(1), kill(2), setitimer(2).
10. AND & OR
Viděli jsme ji struktury, které řešili podmínky, ale podmínky můeme ještě více zdokonalit. Chceme-li třeba, aby pro vykonání následujícího příkazu byly splněny dvě či více podmínek najednou, nebo aby byla splněna alespoň některá z několika podmínek, pouijeme právě znaky || nebo && mezi jednotlivými podmínkami. Znaky || znamenají nebo (OR, logický součet). Pokud je alespoň jedna z podmínek oddělených těmito znaky true, je výsledek true. Naopak znaky && znamenají a (AND, logický součin). Zde musí být splněny všechny podmínky, aby výsledek byl true.
Zde je příklad pouití:
#!/bin/bash
x=5
y=10
if [ "$x" -eq 5 ] && [ "$y -eq 10 ]; then
echo "Obě podmínky jsou splněny"
else
echo "Nejsou splněny obě podmínky"
fi
Podobné pouití má i logický součet. Následující příklad to ilustruje:
#!/bin/bash
x=3
y=2
if [ "$x" -eq 5 ] || [ "$y -eq 2 ]; then
echo "Alespoň jedna podmínka je splněna"
else
echo "Není splněna ádná podmínka"
fi
Další vyuití konstrukcí AND a OR je v tzv. seznamech. Konstrukce seznamu AND umoňuje provádět sadu příkazů tím způsobem, e další příkaz je proveden jen v případě úspěšného provedení všech předchozích příkazů. Má následující syntaxi:
příkaz1 && příkaz2 && příkaz3 && ...
Začne se zleva, je proveden první příkaz a vrátí-li hodnotu true, provede se další příkaz vpravo od něj. Tak to pokračuje, dokud některý z příkazů nevrátí hodnotu false a tím provedení seznamu skončí. Konstrukce && testuje hodnotu předchozího příkazu.
Kadý příkaz je prováděn nezávisle, take v jednom seznamu můeme smíchat mnoho různých příkazů, jak plyne z níe uvedeného skriptu. Seznam AND vrátí hodnotu true, kdy jsou všechny příkazy úspěšně provedeny, v opačném případě vrátí hodnu false.
V následujícím skriptu provedeme příkaz touch file_one (čím kontrolujeme existenci souboru file_one a pokud neexistuje, tak ho vytvoříme) a potom odstraníme soubor file_two. Potom pomocí seznamu AND otestujeme existenci kadého ze souboru a vypíšeme nějaký text.
#!/bin/bash
touch file_one
rm -f file_two
if [ -f file_one ] && echo "hello" && [ -f file_two ] && echo "there"
then
echo -e "in if"
else
echo -e "in else"
fi
exit 0
Výstup programu bude následující:
xconsole$ ./skript.sh
hello
in else
Jak to funguje?
Příkazy touhc a rm zajistí poadovaný stav souborů v aktuálním adresáři. Seznam && pak provede příkaz [ -f file_one ], který bude úspěšný, provede se příkaz echo. Ten bude také úspěšný (příkaz echo vdy vrací hodnotu true). Potom je proveden třetí test, [ -f file_two ], který sele, protoe tento soubor neexistuje. Jeliko byl poslední příkaz neúspěšný, neprovede se poslední příkaz seznamu echo. Výsledek seznamu && je false, protoe jeden z příkazů seznamu selhal, tim pádem se provede vštev else příkazu if.
Konstrukce seznamu OR umonuje provádět skupinu příkazů, dokud jeden nevrátí hodnotu true, pak skončí. Syntaxe je následující:
příkaz1 || příkaz2 || příkaz3 || ...
Příkazy jsou prováděny zleva, jeden po druhém. Tak to pokračuje, dokud některý z příkazů nevrátí hodnotu true a tím provádění seznamu skončí.
Seznam || je podobný seznamu && s tím rozdílem, e nyní musí předchozí příkaz selhat.
Následující příklad je pouze modifikací příkladu minulého, liší se pouze v pouítí seznamu OR místo seznamu AND a také nevytvoří soubor file_one. Průběh však bude díky této konstrukci jiný.
#!/bin/bash
rm -f file_one
if [ -f file_one ] || echo "hello" || echo "there"
then
echo -e "in if"
else
echo -e "in else"
fi
exit 0
Výstup programu bude následující:
xconsole$ ./skript.sh
hello
in if
Jak to funguje?
První dva řádky jen nastavují soubory pro zbytek skriptu. První příkaz [ -f file_one ], sele, protoe daný soubor neexistuje. pak je proveden příkaz echo. Ten vrátí hodnotu true a překvapivě ji nejsou ádné další příkazy seznamu || provedeny. Příkaz if bude úspěšný, protoe jeden z příkazů seznamu || (echo) vrátil hodnotu true.
Výsledek obou těchto konstrukcí je výsledkem posledního provedeného příkazu.
Seznam ne vyhodnocován podobným způsobem, jakým je v jazyce C vyhodnocováno víc podmínek. K určení výsledku je proveden jen minimální počet příkazů. Příkazy, které ji výsledek nemohou ovlivnit, se neprovedou. Tomu říkáme tzv. zkrácené vyhodnocování.
Zkombinování těchto dvou konstrukcí dostáváme "ráj logiků". Vyzkoušejte:
[ -f file_one ] && příkaz pro true || příkaz pro false
Bude-li test úspěšný, provede se první příkaz, v opačném případě druhý. S těmito méně obvyklými seznamy je vdy lépe trošku experimentovat.
Pokud chcete pouít víc příkazů na místě, kde je povolen příkaz jeden, například v seznamu AND nebo OR, můete si pomoci sloenými závorkami a vytvořit blok příkazů. V aplikaci, kterou si ukáeme dále, se například setkáte s následujícím kódem:
get_confirm && {
grep -v "^${cdcatnum}," $tracks_file > temp_file
mv $temp_file $tracks_file
echo
add_record_tracks
}
11. Pouití argumentů
Kdy píšete do příkazové řádky název nějakého programu, většinou k němu připíšete i nějaké paramtery, které mění chování programu. Parametry také můete napsat, kdy spouštíte nějaký skript. V této kapitole si ukáeme, jak tyto parametry ve skriptu pouít.
Tyto argumenty jsou uloeny v proměnných. Proměnná $# uchovává počet argumentů předaných programu. Jednotlivé argumenty jsou uloeny v proměnných $0, $1, $2,... Je tedy vidět, e jsou uloeny v proměnných číslovaných od 0 do počtu parametrů, přičem v proměnné $0 je uloen název programu. Argumenty programu předané jsou a v proměnných 1 a více. Parametrů můe být celkem 9. Nyní bude následovat příklad, ve kterém se parametry vyuijí:
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Pouití: $0 argument."
fi
echo "První a jediný argument předaný skriptu je $1"
Tento program očekává pouze jeden parametr, aby se spustil program. Jestlie bylo předáno více nebo méně ne jeden parametr, vytiskne zprávu pouití. Jestlie byl jeden argument předán, bude také vytištěn.
Zde by bylo vhodné si uvést některé proměnné prostředí
Pokud by se vyskytla situace, e skriptu bude předáno více ne devět parametrů, samozřejmě existuje jednoduchý způsob, jak přistoupit i k dalším parametrům. Je to příkaz shift.
Pokud budete chtít přistoupit ke všem parametrům skriptu jako k jediné proměnné, pouijte ke čtení parametrů proměnnou $*. Ta vrátí seznam všech parametrů uloených v jedné proměnné a oddělených prvním znakem uvedeným v proměnné IFS. Pouijete-li však pro přístup proměnnou $@, vrátí vám toté co $*, ale nepouívá proměnnou prostředí IFS. Přesný rozdíl mezi $* a $@ specifikuje X/Open.
Některé proměnné prostředí
$HOME Domovský adresář aktuálního uivatele
$PATH Seznam adresářů oddělený dvojtečkami, ve kterých se mají hledat příkazy
$PS1 Prompt příkazové řádky, obvykle $
$PS2 Druhý prompt, který se vyuívá při dodatečném vstupu, obvykle >
$IFS Oddělovač polí. Seznam znaků, které slouí k oddělování slov, kdy shell čte vstup, obvykle mezera, tabulátor a znak nový řádek.
$0 Název skriptu shellu
$# Počet předaných parametrů
$$ ID procesu skriptu, které se často pouívá uvnitř shellu ke generování jedinečných názvů dočasných souborů, například /tmp/tmpfile_$$
12. Přesměrování a roury
V normální situaci, kdy je prováděn výstup skriptu, je to standarně na obrazovku. Například kdy se zadá příkaz na vypsání řetězce, vypíše se implicitně na obrazovku terminálu. Přesměrujeme-li však výstup někam jinam pomocí znaku > (přesměrování) a za to soubor, kam se výstup přesměruje. Příklad přesměrování:
xconsole$ echo "Hello wolrd" > foo.file
xconsole$ cat foo.file
Hello world
V ukázce je tedy vypsán řetězec "Hello world" a to do souboru do kterého byl přesměrován výstup. Následující příkaz cat vypíše obsah onoho souboru. Tento soubor nemusí existovat. S operátorem > je však jeden problém. Jeho pouitím se toti přepíše jakýkoliv soubor do kterého je výstup přesměrován. Proto existuje ještě jeden operátor >>, který výstup přesměruje na konec daného souboru. Podobně, jak kdy se v jazyce C otevírá soubor příkazem open s flagem O_APPEND.
Nakonec si ukáeme roury. Roury umoňují pouít výstup programu jako vstup programu jiného. Roury se tvoří operátorem | (nejde o malé L). Tento znak se vytvoří na angl. klávesnici jako SHIFT-\. Následuje příklad roury:
xconsole$ cat /etc/passwd | grep xconsole > foo.file
xconsole$ cat foo.file
xconsole:x:1002:100:X_console,,,:/home/xconsole:/bin/bash
Zde jsme přečetli soubor /etc/passwd a výstup jsme rourou předali jako vstup programu grep, který má nalézt řetězec xconsole. Konečný výstup je přesměrován a uloen do souboru foo.file. Můeme tedy vidět, e přesměrování a roury můe být pro naše skripty uitečná vlastnost UNIXu.
13. Dočasné soubory
Často potřebujeme vytvořit dočasný soubor. Jak ale zajistit, e soubor námi vytvořený bude v systému jedinečný? Celkem jednoduše. Soubor vytvoříme pomocí příkazu touch. Zvolíme název a jako příponu pouijeme znaky "$$". Tím zajistíme, e vytvoříme jedinečný soubor, protoe příkaz touch nahradí znaky $$ číslem, které se v adresáři u tohoto souboru s největší pravděpodobností nevyskytuje, protoe je to jedinečný ID identifikátor procesu. Zde je příklad vytvoření:
xconsole$ touch hello
xconsole$ ls
hello
xconsole$ touch hello.$$
xconsole$ ls
hello hello.689
14. Návratové hodnoty
Spousta programů vrací nějakou hodnotu, která závisí na tom, jak program skončí. Například podíváte-li se na manuálovou stránku příkazu grep, zjistíte, e příkaz vrátí 0 jestlie hledané nalezl a 1 jestli nenašel nic. Proč by jsme měli zjišovat návratovou hodnotu programu? Pro různé důvody. Toto uváení nechme na kadém uivateli. Jedna z moností je například, chceme-li pomocí skriptu zjistit, zda-li je v systému uivatel "karel". Nahlédneme do souboru /etc/passwd a budeme pátrat po slovu karel. Příklad skriptu je zde:
#!/bin/bash
if grep "karel" /etc/passwd > /dev/null
then
echo "Uivatel karel v systému existuje"
else
echo "Uivatel karel v systému neexistuje"
fi
Nyní kdy spustíme skript, bude program grep vyhledávat v souboru /etc/passwd slovo karel. Nalezne-li, vrátí true a funkce if tedy vykoná výpis, e uivatel existuje. Další monost skriptu, který bude vykonávat toté si ukáeme nyní. Budeme však pouívat návratovou hodnotu trochu jinak. Návratová hodnota se toti uloí do speciální proměnné, která se jmenuje $?.
#!/bin/bash
# hledání karla a veškerý výstup je přesměrován do /dev/null:
grep "karel" > /dev/null 2>&1
# uloí návratovou hodnotu a podle ní vykoná:
if [ "$?" -eq 0 ]; then
echo "Nenalezen."
exit
else
echo "Nalezen."
fi
Návratovou hodnotu můe mít také funkce ve vašem skriptu. Toho se docílí přidáním řádku return a příslušné hodnoty. Kdy shell dorazí na tento řádek při vykonávání funkce, je funkce ukončena s návratovou hodnotu, která je stanovena jako parametr za slovem return. Malý příklad:
detekce_souboru()
{
# testuje, jestli soubor existuje:
if [ -f /etc/passwd ]; then
echo "Soubor hesel existuje"
return 0
else
echo "Soubor hesel nenalezen."
return 1
}
# načte hodnotu z funkce detekce_souboru:
foo=detekce_souboru
# zjištění hodnoty:
if [ "$foo" -eq 0 ]; then
echo "Soubor existuje"
exit 0
else
echo "Soubor neexistuje"
exit 1
fi hodnota true představuje číslo 0 a hodnota false představuje číslo 1
16.1 Příkaz break
Tento příkaz slouí k odskoku z cyklu for, while nebo until ještě před splněním řídicí podmínky. Příkazu break můete předat číselný parametr, který udává, kolik cyklů má přerušit. Tím ale můete hodně znepříjemnit čtení skriptů, take vám jeho pouití nedoporučuji. Příkaz break implicitně zruší jednu úroveň cyklu.
#!/bin/bash
rm -rf fred*
echo > fred 1
echo > fred 2
mkdir fred3
echo > fred4
for file in fred*
do
if [ -d "$file" ]; then
break;
fi
done
echo "První adresář fred byl $file"
rm -rf fred*
exit 0
16.2 Příkaz :
Příkaz dvojtečka je nulový příkaz. Příleitostně se pouívá ke zjednodušení logiky podmínek, kde zastupuje hodnotu true. Protoe se jedná o zabudovaný příkaz, běí rychleji ne příkaz true, i kdy je mnohem méně čitelný.
Můete se s ním setkat v podmínce cyklů while. Zápis while : znamená nekonečný cyklus, který se ale běněji zapisuje jako while true.
Kostrukce : je uitečná při podmíněném nastavování proměnných. Například:
: ${var:=value}
Pokud bychom neuvedli znak:, snail by se shell vyhodnotit proměnnou $var jako příkaz.
V některých, zejména starších skriptech se můete setkat s pouitím dvojtečky na začátku řádku, kde uvádí komentář, ale moderní skripty by měly na začátku řádku komentáře vdy uvádět znak #, protoe je to efektivnější.
#!/bin/bash
rm -rf fred
if [ -f fred ]; then
:
else
echo "Soubor fred neexistuje."
fi
exit 0
16.3 Příkaz continue
Podobně jako stejnojnenný příkaz jazyka C spustí tento příkaz další iteraci (průchod) cyklů for, while nebo until, přičem je proměnné cyklu přiřazena další hodnota ze seznamu. Příklad:
#!/bin/bash
rm -rf fred*
echo > fred1
echo > fred2
mkdir fred 3
echo > fred4
for file in fred*
do
if [ -d "$file" ]; then
echo "přeskakuji adresář $file"
continue
fi
echo soubor je $file
done
rm -rf fred*
exit 0
Příkaz continue můe mít nepovinný parametr, který je číslo cyklu, jím se má pokračovat, take můete částečně vyskočit z vnořených cyklů. Tento parametr je však jen zřídka pouíván, protoe často velice stíí pochopení skriptů. Například skript:
#!/bin/bash
for x in 1 2 3
do
echo before $x
continue 1
echo after $x
done
exit 0
vrátí následující výstup:
before 1
before 2
before 3
16.4 Příkaz .
Příkaz tečka provede příkaz v aktuálním shellu:
xconsole$. ./shell_script
Normálně, kdy skript provádí externí příkaz nebo skript, je vytvořeno nové prostředí (podřízený shell), příkaz je proveden v tomto novém prostředí a prostředí je pak zrušeno, s výjimkou návratového kódu, který je vrácen rodičovskému shellu. Nicméně externí příkazy source a tečka (další dvě synonyma) způsobí spuštění příkazu uvedených ve skripto v rámci stejného shellu, který skript vyvolal.
To znamená, e normálně se změny v proměnných přostředí, které program provede, ztratí. Příkaz tečka naproti tomu umoňuje prováděnému příkazu změnit aktuální prostředí. To je nezřídka uitečné, kdy poutíváte skript jako "obal" pro nastavení prostředí pro pozdější provedení nějakého příkazu. Kdy například pracujete současně na několika různých projektech, zjistíte, e potřebujete spouštět příkazy s různými parametry, třeba kvůli spuštění starší verze kompilátoru při úpravě starého programu.
Ve skriptech shellu funguje příkaz tečka jako direktiva #include jazyka C nebo C++. Ačkoli tento příkaz skript nikam "nezahrne", provede příkaz v aktuálním kontextu, take ho můete pouít k začlenění definic proměnných a funkcí do skriptu.
16.5 Příkaz eval
Příkaz eval umoňuje vyhodnocovat argumenty. je zabudován do shellu a normálně neexistuje jako samostatný příka. Asi nejlépe jeho pouití demonstruje následující příklad, který je přímo ze specifikace X/Open:
foo=10
x=foo
y='$'$x
echo $y
Tento skript vrátí $foo, ale následující
foo=10
x=foo
eval y='$'$x
echo $y
ji vrátí 10. Tudí příkaz eval funguje trochu jako další znak $ - vrátí hodnotu hodnoty proměnné.
Příkaz eval je velmi uitečný, protoe umoňuje generování a spouštění kódu za běhu. Komplikuje ladění skriptů, ale umoňuje provádět věci, které bby normálně byly obtíné, ne-li nemoné.
16.6 Příkaz exec
Příkaz exec má dvě různá pouití. Normálně slouí k nahrazování aktuálního shellu jiným programem. Například následující řádek
exec wall "Děkuji za všechny ryby"
ve skriptu nahradí aktuální shell příkazen wall. Řádky, které ve skriptu následují po příkazu exec, nebudou provedeny, prote shell, který skript prováděl, ji neexistuje.
Druhý způsob pouití příkazu exec umoňuje upravit deskriptory souboru:
exec 3< soubor
Výše uvedený zápis způsobí, e deskriptor tři bude otevřen pro čtení ze souboru soubor. Pouívá se jen zřídka.
16.7 Příkaz exit n
Příkaz exit způsobí ukončení skriptu s návratovým kódem n. Pokud ho pouijete v příkazovém řádku kteréhokoliv interaktivního shellu, pak vás tento příkaz odhlásí. Pokud váš skript skončí, ani by specifikoval nějaký návratový kód, pouije se jako návratorý kód stav posledního příkazu provedeného ve skriptu. Vdy je dobré nějaký návratový kód uvést.
Při programování skriptů shellu znamená 0 úspěšné ukončení, 1 a 125 včetně pak chybové kódy, které mohou skripty vyuívat. Zbylé hodnoty jsou rezervovány: 126 - soubor nebyl spustitelný, 127 - příkaz nenalezen a 128 a vyšší - objevil se nějaký signál.
Toto je jednoduchý příklad, který vrátí nulu, pokud v aktuálním adresáři existuje soubor .profile.
#!/bin/bash
if [ -f .profile ]; then
exit 0
fi
exit 1
Pokud si libujete v hutných skriptech, můete tento skript přepsat za pomoci seznamů AND a OR.
[ =f .profile ] && exit 0 || exit 1
16.8 Příkaz export
Příkaz export zpřístupní proměnnou, kterou mu předáte jako parametr, podřízeným shellům. Proměnné vytvořené v shellu implicitně nejsou přístupné dalším (podřízeným) shellům vyvolaným z tohoto skriptu. Příkaz export vytvoří proměnnou prostředí předanou jako parametr, která pak bude přístupná jiným skriptům, a programům vyvolaným z tohoto programu. Odborně řečeno, exportované proměnné vytvoří proměnné prostředí v libovolném dceřiném procesu odvozeném od tohoto shellu. To nejlépe ilustrují dva skripty nazvané export1 a export2.
Nejprve skript export2:
#!/bin/bash
echo "$foo"
echo "$bar"
Nyní skript export1. Na konci skriptu voláme skript export2.
#!/bin/bash
foo="The first meta-syntactic variable"
export bar="The second meta-syntatic variable"
./export2
Spustíme-li skript export1, dostaneme následující výstup:
xconsole$ export1
The second meta-syntatic variable
xconsole$
První řádek je prázdný, protoe proměnná foo nebyla ve skriptu export2 dostupná, take byla vyhodnocena jako prázdná. Předáme-li příkazu echo prázdnou proměnnou, vypíše jen znak nový řádek.
Jakmile byla proměnná exportována z shellu, bude exportována do všech skriptů spuštěných z tohoto shellu a také do všech dalších shellů, které z něj budou spuštěny. Pokud by skript export2 volal jiný skript, také on by měl k dispozici hodnotu proměnné bar.
Příkazy set -a nebo set -allexport exportují všechny nově vytvořené proměnné.
16.9 Příkaz printf
Příkaz printf je dostupný jen v moderních shellech (je dostupný v bash). Podle specifikace X/Open byste mu při vytváření formátovaného výstupu měli dávat přednosti před příkazem echo. Jeho syntaxe je:
printf "formátovací řetězec" parametr1 parametr2 ...
Formátovací řetězec je (s určitými omezeními) podobný formátovacímu řetězci v jazyce C či C++. Především nejsou podporovány reálné proměnné, přotoe veškerá aritmetika v shellu probíhá v oboru celých čísel. Formátovací řetězec je tvořen libovolnou kombinací písme, řídících sekvencí a konverzních specifikátorů. Všechny jiné znaky ne % a \ se na výstupu objeví v původní podobě.
Řídící sekvence Popis
\\ Znak zpětné lomítko
\a Varování (pípnutí)
\b Znak vysunutí stránky
\n Znak nový řádek
\r Návrat vozíku
\t Znak tabulátor
\v Znak vertikální tabulátor
\ooo Znak, jeho osmičková hodnota je ooo
Konverzní specifikátor Popis
d Vypíše desítkové číslo
c Vypíše znak
s Vypíše řetězec
% Vypíše znak %
Konverzní specifikátor je o něco sloitější, take zde uvedeme jen běně pouívané parametry. Další podrobnosti najdete v manuálu. Konverzní specifikátor je tvořen znakem % následovaným konverzním znakem.
Formátovací řetězec je pak pouit k interpretaci zbylých paramterů a výstupu výsledku.
xconsole$ printf "%s\n" hello
hellox
console printf "%s %d\t%s" "Hi there" 15 people
16.10 Příkaz set
Příkaz set nastavuje proměnné shellu. Můe to být způsob, jak vyuít pole v příkazech, které předávají na výstup hodnoty oddělené mezerami.
Dejeme tomu, e chceme v shellu pouít název aktuálního měsíce. Systém nabízí příkaz date, který vrací řetězec obsahující měsíc, ale my chceme tento měsíc získat odděleně od ostatních polí. Můeme to udělat zkombinováním konstrukce $(...), pomocí které provedeme příkaz date a získáme výsledek (na který se za chvíli podíváme podrobněji) s příkazem set. Měsíc tvoří ve výstupu příkazu date druhou poloku:
#!/bin/bash
echo Datum je $(date)
set $(date)
echo Měsíc je $2
exit 0
Tento program nastavuje seznam parametrů podle výstupu příkazu date a z pozičních parametrů $2 pak získá poadovaný měsíc.
Všiměte si, e jsme na příkazu date demonstrovali způsob nastavení pozičních parametrů. Protoe výstup příkazu date závisí na místním jazyce, ve skutečnosti bychom název měsíce získali pomocí zápisu date +%B. Příkaz date má mnoho dalších parametrů, o kterých se dozvíte víc v manuálových stránkách.
Pomocí příkazu set a příslušných parametrů můeme také řídit chování shellu. Nejčastěji se pouívá set -x, který způsobí, e skript vdy vypíše název právě prováděného příkazu.
16.11 Příkaz unset
Příkaz unset odstraní z prostředí proměnnou nebo funci. Netýká se to ale proměnných určených jen pro čtení, které definoval sám shell, jako například IFS. Příliš často se nepouívá.
Skript
#!/bin/bash
foo="Hello world"
echo $foo
unset foo
echo $foo
vypíše nejdříve pozdrav Hello world a potom prázdný řádek.
Zápis foo= má podobný efekt jako příkaz unset ve výše uvedeném příkladu, ale nastavení nulové hodnoty řetězce nemá stejný účinek jako odstranění proměnné foo z prostředí.
16.12 Příkaz shift
Příkaz shift způsobí posun všech pozičních parametrů, take z pozičního parametru $2 se stane $1, z $3 bude $2 atd. Hodnota $1 zmizí, zatímco hodnota parametru $0 bude zachována. Pokud příkazu shift předáte číselný parametr, posunou se poziční parametry o daný počet míst. Ostatní proměnné $*, $@, $# jsou tímto příkazem také ovlivněny.
Příkaz shift je vhodný pro procházení parametrů a pokud váš skript vyaduje deset nebo více parametrů, budete ho potřebovat pro přístup k desátému a vyššímu parametru.
Jako příklad si můeme ukázat sktipt, který projde všechny poziční parametry:
#!/bin/bash
while [ "$1" != "" ]; do
echo "$1"
shift
done
exit 0
17. Žolíkové znaky
Žolíkové znaky jsou obecně silnou stránkou shellu bash. Jsou to vlastně vzory, podle kterých se porovnávají např. názvy souborů. Při jejich tvorbě se pouívají operátory *, ? a výrazy v hranatých závorkách [ ]. Příklad výrazu z olíkovými znaky:
xconsole$ ls /bin/*sh
/bin/ash /bin/bash /bin/bsh /bin/csh /bin/sh /bin/tcsh
Tento program vlastně vypsal všechny shelly dostupné v mém systému, které mám v adresáři /bin. Nejjednodušší zástupné znaky jsou ? a *. Otazník reprezentuje pouze jediný jakýkoliv znak, hvězdička jich reprezentuje libovolné mnoství (i ádný). Je dobré si uvědomit, e pokud chceme vypsat všechny soubory z adresáře, nemusí se pouívat *.* jako v dosu, ale protoe UNIX je nezávislý na příponách, stačí pouze hvězdička jedna (ls *).
Toto je však dostupné i v dosu. UNIX jde ovšem dál, mnohem dál.
Řekněme například, e chceme vypsat všechny shelly v systému, ale pouze ty, které začínají na a a b. Je to velmi jednoduché:
xconsole$ ls /bin/[a,b]*sh
/bin/ash /bin/bash /bin/bsh
Nebo například shelly, které mají jakýkoliv název, kromě těch, co začínají na c:
xconsole$ ls /bin/[^c]*sh /bin/sh
/bin/ash /bin/bash /bin/bsh /bin/sh /bin/tcsh
Do hranatých závorek se píšou znaky, které můou být pouity při expanzi tohoto výrazu. Pokud se však dá před ten konkrétní znak stříška (^), bere se to jako negace, čili tento znak se v řetězci vyskytnout nesmí. V adresáři by se však mohl vyskytnout soubor, který bude začínat na velké C. Tento soubor by ale vypsán byl. Jak tomu zabránit? Takto:
xconsole$ touch /bin/Csh
xconsole$ ls /bin/[^c^C]*sh /bin/sh
/bin/ash /bin/bash /bin/bsh /bin/sh /bin/tcsh
Nebo například chceme v adresáři všem souborům, které začínají na malé písmeno a jsou v adresáři /usr/bin odebrat právo pro zápis. Pro tento úkol můeme pouít následující skript:
#!/bin/bash
for i in /usr/bin/[a..z]*
do
chmod -w i
done
Toto byl úvod do tajemství olíkových znaků. Nakonec bych ještě upozornil na tzv. regulární výrazy, které ovšem jsou olíkovým znakům pouze podobné. Regulární výrazy se pouívají většinou v textových editorech na různé sloité operace s texty, v programech jako awk, Perl, Tk. Ale také programy, které jdou vyuít i při našem skriptování v bash, a to programy grep a egrep. Slouí k vyhledávání řetězců v souborech. Více o těchto programech viz manuálové stránky nebo systém nápovědy info. Například chceme-li vypsat všechny programy jazyka C obsahující funkci main, pouijeme tento zápis:
xconsole§ grep -l 'int.*main*(' *.c
Program (e)grep pouívá pro zápis skutečné regulární výrazy, o kterých se můete dozvědět buď v manuálových stránkách či někde jinde na internetu.
18. Ladění skriptů
Ladění skriptu shellu je většinou poměrně jednoduché, ale také nemáme k dispozici ádné nástroje. V rychlosti si shrneme běné metody ladění.
Kdy dojde k chybě, shell normálně vytiskne číslo řádku, na kterém se vyskytla chyba. Není-li chyba na první pohled zřejmá, můeme pomocí dodatečných příkazůecho zobrazit obsah proměnných a otestovat fragmenty kódu tak, e je interaktivně zapíšeme přímo v shellu.
Protoe jsou skripty interpretovány, nedochází při úpravách a zkoušení k ádnému zdrení při překladu.
Základní způsob vystopování těch nejkomplikovanějších chyb spočívá v nastavení různých voleb shellu. K romu můete vyuít buď volby příkazového řádku při spouštění shellu anebo příkaz set. Tyto volby shrnuje následující tabulka.
Volba příkazového řádku Volba příkazu set Popis
sh -a <skript> set -o noexec set -a Kontroluje jen syntaktické chyby; neprovádí příkazy.
sh -v <skript> set -o verbose set -v Před zpracováním příkazy vypíše.
sh -x <skript> set -o xtrace set -x Po zpracování příkazy vypíše.
set -o nouset set -u V případě pouití nedefinované proměnné vrátí zprávu o chybě.
Volby příkaz set můete zapnout zápisem -o a vypnout +o. Podobně to platí i pro zkrácené zápisy.
Volba xtrace nabízí jednoduché sledování provádění skriptu. Při první zkoušce můete pouít volbu příkazové řádky, ale pokud budete provádět jemnější ladění, můete příznaky xtrace (zapínající a vypínající vypisování příkazů) zařadit do kódu kolem problematické části. Při sledovaném provádění shell vytiskne kadý řádek skriptu s expandovanými proměnnými ještě před jeho provedením. Stupeň expanze určuje (implicitně) počet znaků + na začátku kadého řádku. Znak + můete změnit na jiný pomocí proměnné shellu PS4, která se nastavuje v konfiguračním souboru shellu.
V shellu můete také odchytáváním signálu EXIT zjišovat stav programu při jeho ukončení. Dosáhnete toho, kdy na začátek skriptu umístíte například následující řádek:
tran 'echo Exitting: critical variable = $critical_variable' EXIT