Cyklus for
Na rozdiel od pascalovského, či céčkarského for
u, kde sa v cykle zvyšuje premenná od počiatočnej po koncovú hodnotu, shellovský for
sa drží filozofie for-each
. Očakáva totiž zoznam shellovských slov, cez ktorý postupne iteruje.
#!/bin/sh
for FARBA in cervena oranzova zlta zelena modra indigo fialova
do
echo "$FARBA je farba duhy"
done
Výpis:
cervena je farba duhy
oranzova je farba duhy
zlta je farba duhy
zelena je farba duhy
modra je farba duhy
indigo je farba duhy
fialova je farba duhy
Za pozornosť stojí syntax: do
a done
sú na samostatných riadkoch.
Pozor na medzery (a ďalšie znaky bieleho miesta) a úvodzovkovanie! Takého shellové slová patria do úvodzoviek.
#!/bin/sh
for BEATLE in "Ringo Starr" "Paul McCartney" "George Harrison" "John Lennon"
do
echo "$BEATLE je clen Beatles"
done
Výpis:
Ringo Starr je clen Beatles
Paul McCartney je clen Beatles
George Harrison je clen Beatles
John Lennon je clen Beatles
Generovanie zoznamu
Samozrejme, zoznam vo for
e sa málokedy uvedie v skripte ručne. V mnohých prípadoch bude výsledkom behu príkazu.
Vieme, že zoznam používateľov v systéme získame cez
cut -d":" -f1 < /etc/passwd
Na výstupe sa zjaví každé meno na samostatnom riadku, čo však možno chápať ako zoznam mien, ktoré sú oddelené znakom nového riadka. Cyklus for
si s tým ľahko poradí.
Stačí výsledok uzavrieť do prostredia pre subshell $(...)
:
for USER in $( cut -d":" -f1 < /etc/passwd )
do
echo "Overujem pouzivatela $USER"
done
Iterácia cez zoznam súborov
Často sa for
používa na spracovanie zoznamu súborov. Skvelo sa snúbi s expanziou ciest (pathname expansion).
for FILE in *.mp3
do
echo "V domovskom priecinku je $FILE"
done
Expanzia si poradí aj s názvami súborov, v ktorých sú medzery. Samozrejme, stále ste obmedzení možnosťami expanzie ciest: ak potrebujete filtrovať napr. len adresáre, musíte to urobiť ručne vo vnútri cyklu cez if
.
Zlá iterácia cez zoznam súborov
Rozhodne však nerobte toto:
#!/bin/sh
for FILE in $(ls ~ -1)
do
echo "V domovskom adresari je $FILE"
done
Táto verzia bude fungovať len vtedy, pokiaľ nebudú v domovskom adresári názvy súborov s medzerou. V mnohých prípadoch to zdanlivo bude fungovať:
V domovskom adresari je /home/novotnyr/for-test.sh
V domovskom adresari je /home/novotnyr/public_html
Predstavme si takýto obsah:
for-test.sh
public_html
moje fotky
Príkaz ls ~ -1
následne expanduje na
for-test.sh
public_html
moje
fotky
Cyklus potom bude prechádzať cez jednotlivé slová oddelené znakom \n
, čo ale spôsobí…beda:
V domovskom adresari je /home/novotnyr/for-test.sh
V domovskom adresari je /home/novotnyr/public_html
V domovskom adresari je /home/novotnyr/moje
V domovskom adresari je /home/novotnyr/fotky
To asi nie je to, čo chceme.
Pokiaľ chcete robiť komplikované vyhľadávanie, for
u sa treba vyhnúť. Výstup z príkazu, ktorý je rozseknutý podľa bieleho miesta, je totiž ťažké ohnúť. Oveľa lepšie je použiť kombináciu find
/ while
, alebo ešte lepšie find
/ xargs
.
Cyklus v GNU nástrojoch (seq
)
Ak silou-mocou potrebujeme iterovať cez čísla a máme šťastie na GNU nástroje, môžeme použiť seq
. Klasické použitie:
novotnyr@s:~$ seq 10
1
2
3
4
5
6
7
8
9
10
Už je vidieť, ako to môžeme použiť v cykle for
:
for CISLO in $(seq 10)
do
echo "Iteracia c. $CISLO"
done
Cyklus v BSD (jot
)
MacOSási a BSĎáci majú analógiu:
jot - 1 10
Cyklus v POSIX
Ak chcete byť striktne POSIXoví a neuchýliť sa k bashizmom či kornshellizmom, neostáva nič iné, než použiť while
.