DETAIL: Bash


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. Takže 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. Jestliže 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ůležité, protože 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čí. Takže čeho jsme docílili? Použili jsme příkaz shellu echo, který zajistil výpis textu na obrazovku. Jeho paramtrem je právě ten text. Je také možný 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 užitečnější program. Program, který přesune všechny soubory do adresáře, a pak tento adresář smaže 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é možné 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 použití 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 použití na standardní výstup a bez­chybně 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 uložena 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 užitečný a efektivnější. Velmi důležitá 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 každý 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. Každá 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ůležitě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 použit příkaz test. Příkaz na základě přepínače -f určí, zda-li je /etc/foo soubor. Další možnosti přepínače příkazu test shrnuje následující tabulka. Je také možno 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ý


Jestliže 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 umožní, ž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 možné 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ůležité, protože 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ý vždy 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ý, protože systém musí vždy 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 užitečný.

V následujícím příkladu použijeme proměnnou x, která bude při každé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ší možnosti 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 možné 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 použita 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ší možnosti 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. Každý 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 použití na standardní výstup a bez­chybně 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 každém průběhu cyklu bude mít proměnná jinou hodnotu. Například chcete napsat skript, který desetkrát vytiskne každou 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 každém jednotlivém průběhu cyklu. Tyto hodnoty však v našem cyklu nejsou použity (ale samozřejmě použity 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 použity:

#!/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 možné 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éž použity řetězce. Další užitečný příklad ukáže, jak je možné přidat všem souborům v aktuálním adresáři příponu html. Ukáže, že je tedy možné 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ž každé 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 považují vždy za jeden parametr, a to jako jeden řetězec. Například použijeme-li příkaz:

xconsole$ mkdir hello world
xconsole$ ls -F
hello/     world/

Uvidíme to, co po použití příkazu ls -F vidíme. To jest vytvořené dva samostatné adresáře. Ale pokud použijeme 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ž každý 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 použití dvojitých uvozovek se provede nahrazení $x za konkrétní hodnotu, kdežto 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 možná 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, protože 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éž možné 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 udržována a může být nepřesná nebo neúplná. Autoritativním zdrojem je Texinfo dokumen­tace.

Tato manuálová stránka popisuje GNU verzi příkazu expr. Příkaz expr vyhodnotí výraz a vypíše výsledek na stan­dardní výstup. Každé 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 nevyžaduje, ale jejich použití 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'.

& Jestliže 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í; jestliže převod na čísla není možné uskutečnit, provede abecední porovnání. Vrátí 1, jestliže 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 argu­menty jsou napřed převedeny na čísla; je chybou, jestliže není možné 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, jestliže není možné převod na čísla provést.

: Porovnání řetězce s regulární výrazem. Oba argu­menty 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 inter­pretová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ě, jestliže 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 jestliže v regulárním výrazu bylo `\(' a `\)', je výsledkem prázdný řetězec, jinak je výsledkem 0. Může být použit 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. Jestliže 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ů. Jestliže 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 možné použít kulaté závorky. Klíčová slova nemohou být použita 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 použití na standardní výstup a bez­chybně 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 použit pro vypsání poslední složky jména souboru uloženého v proměnné a (hodnota v a nemusí obsahovat `/'):

expr $a : '.*/\(.*\)' \| $a

-- metaznaky shellu je nutné dávat do uvozovek či apo­strofů.

Příkaz expr nastavuje následující kódy ukončení (exit sta­tus):

0 jestliže výsledek není ani prázdný řetězec ani 0,

1 jestliže výsledek je prázdný řetězec nebo 0,

2 pro chybné výrazy.

7. Čtení uživatelské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 uživatele (popř. na vstup čtený ze souboru). Příkaz uživatelského vstupu je příkaz read. Jedná se o vnitřní příkaz shellu. Příkaz vyžaduje 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. Využití 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 uživatel vždy zadá to, co očekáváme a je tedy nutné se proti tomu bránit. Je však vhodné uživatele na špatně zadané data upozorňovat citlivě a ne tak, aby si uživatel z toho vydedukoval, že si o něm myslíme, že je blbec. Jestliže uživatel 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 rozložit 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 vždy 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 složený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 vždy 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ší možný 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í, takže 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í složené 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 vždy 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, protože se všechny skripty provádějí od začátku, takže pokud umístíte všechny funkce před první volání libovolné funkce, budou vždy 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í uloženy 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 možné 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á uživatele, 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čí, takže bude běžet dál.

Chcete-li však, aby byl signál ignorován úplně, použijte jako akci "''". Chcete-li pak někde v programu již standardní zpracování signálu, použijte 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ý uživatelem

SIGUSR2 31,12,17 A Signál 2 definovaný uživatelem

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 použita 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 pro­cesu (core dump).

D Tento signál standardně pozastaví provádění pro­cesu.

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, použijeme 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 použití:

#!/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é použití 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ší využití 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.

Každý příkaz je prováděn nezávisle, takže 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 každé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í požadovaný 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 vždy vrací hodnotu true). Potom je proveden třetí test, [ -f file_two ], který selže, protože tento soubor neexistuje. Jelikož byl poslední příkaz neúspěšný, neprovede se poslední příkaz seznamu echo. Výsledek seznamu && je false, protože jeden z příkazů seznamu selhal, tim pádem se provede vštev else příkazu if.

Konstrukce seznamu OR umožnuje 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 ], selže, protože 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ý, protože 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 vždy 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 složený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. Použití 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 uloženy v proměnných. Proměnná $# uchovává počet argumentů předaných programu. Jednotlivé argumenty jsou uloženy v proměnných $0, $1, $2,... Je tedy vidět, že jsou uloženy v proměnných číslovaných od 0 do počtu parametrů, přičemž v proměnné $0 je uložen 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 využijí:

#!/bin/bash

if [ "$#" -ne 1 ]; then
  echo "Použití: $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. Jestliže bylo předáno více nebo méně než jeden parametr, vytiskne zprávu použití. Jestliže 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é, použijte ke čtení parametrů proměnnou $*. Ta vrátí seznam všech parametrů uložených v jedné proměnné a oddělených prvním znakem uvedeným v proměnné IFS. Použijete-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 uživatele

$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 použití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 uložen do souboru foo.file. Můžeme tedy vidět, že přesměrování a roury může být pro naše skripty užiteč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 použijeme znaky "$$". Tím zajistíme, že vytvoříme jedinečný soubor, protože příkaz touch nahradí znaky $$ číslem, které se v adresáři u tohoto souboru s největší pravděpodobností nevyskytuje, protože 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 jestliže 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 každém uživateli. Jedna z možností je například, chceme-li pomocí skriptu zjistit, zda-li je v systému uživatel "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 "Uživatel karel v systému existuje"
else
  echo "Uživatel 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 uživatel existuje. Další možnost 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ů, takže vám jeho použití 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říležitostně se používá ke zjednodušení logiky podmínek, kde zastupuje hodnotu true. Protože 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 užitečná při podmíněném nastavování proměnných. Například:

: ${var:=value}

Pokud bychom neuvedli znak:, snažil by se shell vyhodnotit proměnnou $var jako příkaz.

V některých, zejména starších skriptech se můžete setkat s použitím dvojtečky na začátku řádku, kde uvádí komentář, ale moderní skripty by měly na začátku řádku komentáře vždy uvádět znak #, protože 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, takže můžete částečně vyskočit z vnořených cyklů. Tento parametr je však jen zřídka používán, protože č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 užiteč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, takže 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 použití 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 užitečný, protože 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 nemožné.

16.6 Příkaz exec

Příkaz exec má dvě různá použití. 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, protže shell, který skript prováděl, již neexistuje.

Druhý způsob použití 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 použijete 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, použije se jako návratorý kód stav posledního příkazu provedeného ve skriptu. Vždy 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ý, protože proměnná foo nebyla ve skriptu export2 dostupná, takže 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řotože 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 složitější, takže 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 použit 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 položku:

#!/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á požadovaný měsíc.

Všiměte si, že jsme na příkazu date demonstrovali způsob nastavení pozičních parametrů. Protože 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 vždy 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ů, takže 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 vyžaduje 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é množství (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 protože 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 použity 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é složité 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, použijeme 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.

Protože jsou skripty interpretovány, nedochází při úpravách a zkoušení k žádnému zdržení 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ě použití 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 každý řá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 každé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

Zpět

 
logo horoskopy
logo humor
logo sms
logo nejhry
logo tri65dni
logo tvp
Seminárky, referáty, skripta, mat. otázky Studijní materiály
Seminárky, referáty, skripta, mat. otázky
    Přihlášení
    Registrace


    Vzhledy:
    Vlastni
    Středa 15. 1. 2025 Svátek má Alice
    Vyhrávej v casino.cz nebo na vyherni-automaty.cz   Prodávej s Pla-Mobilem.cz