Každý programovací jazyk vám umožní větvení programu, tedy instrukce, které jsou možné jen ve chvíli, je-li splněna nějaká podmínka.
Co je pravda a co lež
Pravda je true a lež je false. Mají i číselné zastoupení a to se tvůrcům programovacích jazyků pokaždé hodí do krámu nějak jinak, pro bash je 0 pravda a cokoli jiného je lež.
logická hodnota
příkaz
číselná hodnota
pravda
true
0
nepravda
false
nenula
V tabulce uvádím, že true a false jsou příkazy. Jsou a velmi šikovné. true nedělá nic a dělá to správně (jeho exit status je nulový). false také nedělá nic, ale neúspěšně, jeho exit status je jedna.
Podmíněné spuštění
Nemusíme nutně hned odejít do skriptu, abychom něco spustili podmíněně. Operátor && umí spustit příkaz pouze v případě, že příkaz před ním skončí úspěšně. Naopak operátor || umí spustit příkaz pouze v případě, že příkaz před ním skončí neúpěšně
Nicméně, v prvním případě true dopadlo v pořádku, bylo spuštěno echo uspech, které dopadlo taky v pořádku, na echo neuspech se tedy nedostalo. V druhém případě false dopadlo špatně, echo uspech nebylo spuštěno a proto přišlo na řadu echo neuspech. Myslete na to v případě, že budete tvořit složitější konstrukci, že toto není větvení programu v klasické variantě do dvou větví.
Podmínka if
Syntaxe nejmenší použitelná je nakreslena na obrázku: Je-li splněn v pořádku příkaz (jeho exit status je nulový), pak se provádí příkazy.
if ls neco
then
echo "tak ho vidim"
fi
Pokud ls neco proběhne v pořádku (soubor nebo adresář neco je v aktuálním adresáři), pak je splněna podmínka a spustí se výpis echo "tak ho vidim"
jana@drak:~$ ./skript.sh
ls: cannot access 'neco': No such file or directory
jana@drak:~$ touch neco
jana@drak:~$ ./skript.sh
neco
tak ho vidim
jana@drak:~$
Pokud chcete při kódování psát úsporně a pošetřit řádky, napište if příkaz; then.
Chcete-li rozdělit program do dvou větví, tedy příkazy, co se provádí, když je podmínka splněna, a příkazy, co se provádí, když podmínka není splněna, pak je k dispozici konstrukce if-else.
if ls neco
then
echo "tak ho vidim"
else
echo "neni tu, vyrabim"
touch neco
fi
Pokud ls neco proběhne v pořádku, je splněna podmínka a spustí se výpis echo "tak ho vidim", v opačném případě píše, že nic nevidí a provádí touch neco.
jana@drak:~$ rm neco
jana@drak:~$ ./skript.sh
ls: cannot access 'neco': No such file or directory
neni tu, vyrabim
jana@drak:~$ ./skript.sh
neco
tak ho vidim
jana@drak:~$
Ale je možné se rozdělit rovnou do více větví pomocí příkazu elif. Na obrázku uvádím i else, které nemusíte použít.
Místo podmínky za příkaz if píšu příkaz. Vzpomeňte na příkazytrue a false, které vrací nějaký exit status a podle toho je podmínka splněna nebo nesplněna. Tak to je místo, kde může být libovolný příkaz. Velmi oblíbený je třeba grep
Povšimněte si odsazení příkazů uvnitř podmínky. Nejsou nijak podstatné pro funkci kódu (narozdíl od Pythonu), nicméně když je nebudete používat, budou vaše kódy extrémně nečitelné.
Podmíněný výraz
Varianta, ve které píši za if příkaz, je sice oblíbená, ale někdy chcete konat na základě toho, že něco spočítáte, porovnáte řetězce nebo se podíváte na vlastnosti souboru. K tomu slouží výraz, jehož syntaxe je taková, že jej uzavřete do hranatých závorek (ty poctivě oddělíte mezerami od zbytku kódu) a bash jej vyhodnotí, jestli je pravdivý nebo ne.
Nebudu zde uvádět všechny výrazy, pouze ty, které používám nejčastěji a nejraději. Kompletní seznam najdete kde jinde než v man bash, kde si najděte sekci CONDITIONAL EXPRESSIONS (kousek před půlkou celého výpisu. A věděli jste, že když stisknete / a za něj napíšete nějaký výraz, tak vám najde jeho výskyt? A pak stiskem klávesy n najedete na další výskyt? Ne? Tak to zkuste a hned se vám bude hledat v manuálu lépe.)
výraz
význam
-e soubor
soubor existuje
-d soubor
soubor existuje a je to adresář
-f soubor
soubor existuje a je to obyčejný soubor
-r soubor
soubor existuje a má práva ke čtení (pro toho, kdo dělá test)
-w soubor
soubor existuje a má práva k zápisu
-x soubor
soubor existuje a má práva ke spuštění
soubor1 -nt soubor2
soubor1 je novější než soubor2, porovnává datum poslední změny
-v jméno
proměnná jméno existuje a má nějakou hodnotu
-z řetězec
řetězec je prázný
-n řetězec
řetězec není prázný
řetězec1 == řetězec2
řetězec1 a řetězec2 jsou stejné
řetězec1 != řetězec2
řetězec1 a řetězec2 nejsou stejné
číslo1 -eq číslo2
číslo1 je rovno číslo2
číslo1 -ne číslo2
číslo1 není rovno číslo2
číslo1 -lt číslo2
číslo1 je menší než číslo2
číslo1 -le číslo2
číslo1 je menší a rovno číslo2
číslo1 -gt číslo2
číslo1 je větší než číslo2
číslo1 -ge číslo2
číslo1 je větší a rovno číslo2
Pokud chci celý výraz negovat, přidám před něj vykřičník. Použití vidíte v následujícím skriptu, který se podívá, s jakým parametrem byl spuštěn, a pak zjišťuje, jestli je to existující soubor a jakého typu.
#!/bin/bash
if [ -z $1 ]; then #overim, jestli byl zadany parametr skriptu
echo "neni zadany parametr"
exit 10 #a kdyz nebyl, tak ukoncim skript chybou
fi
if [ ! -e $1 ]; then #overim, jestli parametr je nejaky soubor
echo "zadany parametr neni soubor"
exit 11 #a kdyz nebyl, tak ukoncim skript chybou
fi
#zacinam testovat, jaky typ souboru to je
if [ -f $1 ]; then
if [ -x $1 ]; then
echo "je to obycejny soubor a je spustitelny"
else
echo "je to obycejny soubor"
fi
elif [ -d $1 ]; then
echo "je to adresar"
else
echo "je to specialni soubor"
fi
Výstup pak vypadá takto:
jana@drak:~$ ./co_je_to_za_soubor.sh neco.sh
je to obycejny soubor a je spustitelny
jana@drak:~$ ./co_je_to_za_soubor.sh prazdny/
je to adresar
jana@drak:~$ ./co_je_to_za_soubor.sh poezie/marycka_magdonova.txt
je to obycejny soubor
jana@drak:~$
Spojování logických výrazů pomocí logického součtu a součinu je možné, ale syntakticky přinejmenším nepohodlné, doporučuji se mu spíše vyhnout.
if [ $a -gt 2 ] && [ $a -le 10 ] ; then echo "$a je mezi 3-10"
V předchozím případě musí platit obě podmínky, aby bylo provedeno tělo cyklu, v následujícím příkladu musí pro provedení platit alespoň jedna.
if [ $plat -eq 1000000 ] || [ $plat -eq 0 ] ; then
echo "ok, udelam to"
else
echo "delam zadarmo nebo za milion" ;
fi
Při práci s proměnnými výrazně doporučuju zapřemýšlet, jestli se může stát, že nebudou nabývat příslušné hodnoty a jestli tím nedojde k chybě v běhu.
jana@drak:~$ echo $foo
jana@drak:~$ if [ $foo == ano ] ; then echo "rika ano" ; fi
-bash: [: ==: unary operator expected
Operátor == očekává dva řetězce a dostává jen nic a ano. Proto vyhazuje chybu. Její odstranění je snadné.
jana@drak:~$ if [ "$foo" == ano ] ; then echo "rika ano" ; fi
jana@drak:~$
Podmínka case
V jiných jazycích switch, příkaz, který umožní porovnat jedno slovo (nejčastěji nějakou proměnnou) s různými regulárními výrazy (ano, normálními řetězci taky).
kolik=$(who | cut -d" " -f1 | sort | uniq | wc -l)
case $kolik in
1) echo "jsi tu sam" ;;
2) echo "je tu s tebou jeste nekdo" ;;
3) echo "jste jak svata trojice. ty jsi duch" ;;
4) echo "je vas tu tak akorat do mariase" ;;
5) echo "je vas tu pet. jako v romanu Bylo nas pet." ;;
*) echo "je vas tu mraky" ;;
esac