Skriptovanie v shelli: cyklus `for`

Cyklus for

Na rozdiel od pascalovského, či céčkarského foru, 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 fore 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, foru 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.

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *