Posledně jsme si ukázali, jak vytvořit jednoduchoučký skript, kam jej uložit a jak spustit. Již tedy víme, jak zapsat často vkládanou posloupnost příkazů do textového souboru a vyvolat ji jednoduše zapsáním jména skriptu. To sice může někomu stačit, my ale budeme náročnější.
Skriptování přináší možnosti, kterých na příkazovém řádku dosáhnout vůbec nelze nebo jen velmi těžko. Příkazy ve skriptu totiž nemusejí být otrocky vykonány od prvního do posledního, každý právě jednou. Některé části mohou být provedeny vícekrát, jiné jen za určitých podmínek, v průběhu provádění lze volat další skripty, chování lze ovlivňovat proměnnými.
cyklus for
Dnes pokročíme tím, že se budeme pohybovat v kruhu. Přesněji řečeno v cyklu. To je právě způsob, jak nechat určitou část skriptu provést vícekrát, třeba s různými parametry. Bash zná několik druhů cyklů. My začneme zřejmě nejjednodušším z nich - for. Ten možná mnozí z vás znají, protože se v různých obměnách vyskytuje ve většině počítačových jazyků - od C přes Basic až po PHP.
Za klíčovým slovem for je nutné uvést parametry cyklu. Bash za tímto účelem nabízí dva typy syntaxe s různou funkčností. Na další řádek nebo několik řádků uvedeme všechny příkazy, které se mají v průběhu každého cyklu vykonat, přičemž před prvním z nich musí být uvedeno slovo do (anglicky "udělej, proveď"). Seznam příkazů v cyklu zakončíme dalším klíčovým slovem - done (anglicky "uděláno, provedeno").
Popis začneme syntaxí, která je možná jednodušší, ale méně používaná. Vychází ze tří aritmetických výrazů a ukážeme si ji na jednoduchém příkladu:
for (( a=1 ; $a-4 ; a=$a+1 )) do echo $a done
Smyčka začíná samozřejmě příkazem for. Na druhém řádku je za do příkaz echo, který vytiskne hodnotu proměnné a. Slovem done smyčka končí. Hned za for vidíme pravidla cyklu uzavřená do dvou kulatých závorek. Taková konstrukce v Bashi předznamenává vykonávání aritmetických operací.
První z nich přiřazuje proměnné a hodnotu 1. Provede se pouze na začátku prvního průchodu. Druhý výraz slouží k rozhodování, zda se má smyčka vykonat. K vykonání dojde, pokud bude mít zde uvedený výraz hodnotu různou od nuly. V prvním průchodu je a=1, takže a-4 není nula. Před každým dalším průchodem ale bude proveden třetí výraz, kde se hodnota a zvýší vždy o 1. Ve druhém průchodu tak nabyde hodnoty 2 a ve třetím 3.
Po skončení třetího průchodu bude opět aplikován třetí výraz a hodnota a se tak zvýší na čtyři. Nyní je ovšem výsledkem druhého výrazu (a-4) nula, takže čtvrtý průchod smyčkou již neproběhne. Pokud zapíšete výše uvedenou smyčku do skriptu, uvidíte po jeho spuštění číslice 1, 2 a 3, což je důkazem, že proběhly právě tři průchody smyčkou s těmito hodnotami proměnné a.
Před spuštěním smyčky je dobré si podmínky ještě jednou promyslet, neboť se může snadno stát, že se druhá podmínka jaksi netrefí do nuly a smyčka tak poběží do nekonečna. Pozorní čtenáři si samozřejmě pro takový případ z prvního dílu pamatují chvat první pomoci [Ctrl+c]. Další důležitou věcí, na kterou bych měl upozornit, je, že Bash se většinou nekamarádí s desetinnou čárkou, takže nedoporučuji používání desetinných čísel, dělení apod
for in
Další syntaxí smyčky je výraz for in. Ta postupně přiřazuje určené proměnné hodnoty ze zadaného seznamu. Seznam může nabývat nejrůznějších podob. Začněme opět příkladem
for a in A B C D do echo $a done
Smyčka proměnné a přiřadí postupně hodnoty A, B, C a D. V každém průchodu jednu v pořadí, jak jsou zadány. Smyčka proběhne právě tolikrát, kolik hodnot seznam obsahuje. Výsledkem bude vypsání písmen A, B, C, D, každé na samostatném řádku (příkaz echo totiž defaultně vkládá konec řádku na konec svého výstupu).
Jako seznam lze zadat přímo jména souborů, a to včetně zástupných znaků. Toho lze velmi dobře využít při hromadném zpracování více souborů programem, který umí v parametrech přijmout pouze jeden vstupní soubor. Příkladem budiž program recode, který mění kódování znaků v textových souborech.
Mějme adresář obsahující neurčité množství souborů se jménem končícím na .txt, které jsou v kódovaní CP1250 s konci řádků CRLF. Chceme-li z nich udělat ISO-8859-2 soubory s unixovými konci řádků, stačí se přesunout do onoho adresáře a spustit skript s obsahem:
mkdir ISO for a in *.txt do echo Konvertuje se $a ... recode 1250..l2 $a > ISO/$a done
Na prvním řádku, který není součástí smyčky, takže se provede jen jednou, vytvoříme adresář ISO. V prvním řádku smyčky vypíše echo informaci o tom, který soubor se zpracovává. Dále recode provede konverzi původního souboru a výsledek uloží (díky přesměrování výstupu) pod stejným jménem do adresáře ISO. Na konci bychom tak měli mít adresář ISO zaplněn všemi soubory *.txt z aktuálního adresáře převedenými do ISO-8859-2.
Seznam může být také výsledkem činnosti nějakého příkazu. Ten musí být uzavřen do závorek uvozených znakem $. Zde se často využívá seq, který generuje číselné řady dle zadaných pravidel. Mějme skupinu obrázků na vzdáleném serveru www.masinky.cz/ pod jmény obr1.jpg až obr9.jpg, které chceme stáhnout. K tomu využijeme program wget.
for a in $( seq 9 ) do wget http://www.masinky.cz/obr${a}.jpg done
Po provedení skriptu s touto smyčkou by se v pracovním adresáři mělo objevit 9 stažených obrázků (samozřejmě pokud máte funkční připojení k internetu a cílový server i soubory na něm existují). Při stahování většího objemu dat se hodí takový skript spouštět s časovým zpožděním, tedy v době, kdy spíme a linky jsou méně vytížené. Zde by se mohly hodit příkazy sleep (viz 1. díl seriálu) nebo at (viz man at).
Další možností je použít jako seznam proměnnou, která obsahuje několik skupin znaků oddělených mezerou nebo tabulátorem. To je tak triviální, že to nebudeme ani prezentovat na příkladu. Zajímavou možností, která za ukázku stojí, je využití pole (viz 5. díl seriálu) jako seznamu. Mějme pole lodicky definované zápisem lodicky=( člun plachetnice parník ). Komentovaný přehled získáme smyčkou
for a in ${lodicky[*]} do echo Součástí flotily je $a done
Smyčka v jednom řádku
Ve skriptech se často používají dlouhé smyčky, které obsahují mnoho jiných příkazů, podmínek nebo i vnořených smyček. Proto je nutné rozepsat jejich jednotlivé komponenty do více řádků, jak jsme si ukázali na příkladech. Někdy ovšem chceme jen opakovaně provést jeden příkaz s různými argumenty.
Představme si situaci, kdy nám na nějakém serveru vzniklo v určitém adresáři sto tisíc souborů se jmény soubor000000.txt až soubor100000.txt. My je chceme smazat a tak zadáme rm soubor*.txt a ouvej. Odpovědí nám bude chybová hláška bash: /bin/rm: Příliš dlouhý seznam argumentů.
Z toho vidíme, že Bash neměl problém nahradit konstrukci soubor*.txt sty tisíci odpovídajících výsledků. Program rm ovšem nebyl schopen takovou várku zpracovat. Adresář nemůžeme smazat celý, protože jsou v něm i jiné důležité soubory. Pomůže nám jednoduchá smyčka zapsaná do jednoho řádku s použitím středníků: for a in soubor*.txt ; do rm -f $a ; done.
Závěr
Tak jsme dnes při sezení u počítače konečně udělali také něco pro zdraví - stali jsme se cyklisty. Vedle cyklů for nabízí Bash ještě další dva: while a until. Ty se provádějí na základě platnosti resp. neplatnosti zadané podmínky. Proto si tyto typy smyček představíme až po té, kdy probereme podmínky. A na podmínky se vrhneme hned příště.