Cykly
for var in list
do
commands
done
V každé iteraci je do proměnné var přiřazen jeden prvek ze seznamu list
a poté je provedeno tělo commands. List je seznam oddělený mezerami. Ten
můžeme vytvořit přímo, nebo jej získáme jinak, například pomocí expanze jmen.
# list sestaveny primo
for v in monday tuesday wednesday
do
echo ${v}
done
# list ziskany expanzi
# pro kazdou (viditelnou) polozku v adresari addr zavolame utilitku file
addr=logs
for f in ${addr}/*
do
file ${f}
done
Při tvorbě seznamu a jeho zpracování je nutné být opatrný, pokud některé položky
obsahují mezery. Takové položky lze v ručně vytvořeném seznamu vyznačit pomocí
uvozovek nebo apostrofů. Pokud je seznam vytvořen strojově, tuto možnost nemáme.
Dělení řetězce na seznam položek se řídí obsahem proměnné IFS (podrobně viz
Dělení slov a IFS). Její hodnotou
je řetězec znaků, které chápeme jako oddělovače položek. Výchozí oddělovače jsou
mezera, nový řádek a tabulátor. V následujícím příkladu změníme tuto proměnnou
tak, abychom mohli přistoupit k jednotlivým adresářům v proměnné PATH.
IFS=:
for dir in ${PATH}
do
echo -n ${dir}
echo ": $(ls ${dir} | wc -l) polozek"
done
Při nastavování IFS můžeme narazit na problém, jak tam přidat některý
z výchozích znaků. K tomu lze použít znakovou expanzi shellu
$'znak'
Výraz $'\n' tak například expanduje na znak nového řádku; další sekvence jsou
v podkapitole Uvozování.
Seznam položek lze produkovat i pomocí příkazu. Na místě list v cyklu můžeme
dát spuštění nějakého programu v podshellu a v cyklu zpracovat jeho standardní
výstup. V následujícím příkladu zpracujeme obsah souboru /etc/passwd.
# zapamatujeme si puvodni IFS
OLD_IFS=${IFS}
# nova hodnota IFS, soubor prochazime po radcich
IFS=$'\n'
for entry in $(cat /etc/passwd)
do
# tady nastavime IFS nastavime na dvojtecku
# nemusime mit strach, ze pokazime IFS pro vnejsi cyklus
# tam se pamatuje puvodni nastaveni na novy radek
# tj. vyznam ma pouze hodnota IFS na zacatku cyklu
IFS=:
for value in ${entry}
do
echo " ${value}"
done
done
# tady IFS obsahuje dvojtecku, obnovime puvodni hodnoty
IFS=${OLD_IFS}
Další typ cyklu připomíná jazyk C, nebudeme jej tedy blíže komentovat, čtenáři jistě stačí následující příklad
for (( i=1; i <= 10; i++ ))
do
echo ${i}
done
Cyklus while funguje také podobně jako v jazyku C. Dokud platí podmínka,
opakuje se tělo cyklu. Pro podmínky platí podobné zásady jako pro podmínky
konstrukce if. U cyklu navíc můžeme místo podmínky napsat posloupnost řádků,
z nichž pouze poslední je interpretován jako podmínka. Zbylé řádky se spustí
vždy na začátku iterace, před vyhodnocením podmínky.
# cisla 10...0 se vypisi pred podminkou a uvnitr cyklu,
# cislo -1 se vypise jenom pred podminkou
var=10
while echo "hodnota pred podminkou: ${var}"
[ ${var} -ge 0 ]
do
echo "hodnota uvnitr cyklu: ${var}"
var=$[${var} - 1]
done
Konstrukce until je analogická while s tím, že cyklus končí (nikoliv
pokračuje) v momentě, kdy je podmínka pravdivá.
Příkazem break lze okamžitě ukončit vykonávání cyklu, v jehož těle se příkaz
nachází. Příkazu break lze volitelně předat numerický argument (přirozené
číslo), a ten potom přeruší některý z vnějších cyklů v kódu obsahujícím vnořené
cykly. Argument 1 označuje aktuální cyklus, argument 2 cyklus obsahující aktuální
cyklus atd.
for v1 in prvni druha treti
do
for v2 in 10 20 30 40 50
do
for v3 in x y z
do
break # prerusi cyklus s promennou v3
break 1 # prerusi cyklus s promennou v3
break 2 # prerusi cyklus s promennou v2
break 3 # prerusi cyklus s promennou v1
done
done
done
Příkazem continue lze přerušit vykonávání aktuální iterace cyklu, jako bychom
ve skriptu skočili na konec těla cyklu. Podobně jako break lze continue
předat numerický argument, určující kterého cyklu se příkaz týká.
Standardní výstup cyklu (tedy vše, co se během cyklu vytiskne) lze přesměrovat
do souboru nebo rourou. Přesměrování se píše za klíčové slovo done na konci
těla cyklu.
# vypise adresare setrizene podle poctu polozek
IFS=:
for dir in ${PATH}
do
echo -n ${dir}
echo " $(ls ${dir} | wc -l)"
done | sort -r -k 2 # tady presmerujeme rourou do prikazu sort