Egész szám használata ciklusváltozóként sok programnyelvben gyakori, de minden programnyelven egy kicsit másképp történhet és más buktatói lehetnek. Ebben a rövid cikkben egy olyan, Bash-ben felmerülő buktatóról írok, amit talán még te sem ismertél. Tudtad-e például, hogy egy egyszerű inkrementálás vagy dekrementálás a szkript leállását okozhatja? Mondtam én...
Nézzünk egy egyszerű ciklust, ahol 0-tól 10-ig számolunk.
i=0
while (( i <= 10 )); do
echo -n "$i "
(( i++ ))
done
echo
A kimenet tökéletes, a számok megjelennek 0-tól 10-ig.
Sokszor hasznos viszont, ha a Bash szkript elején beállítod, hogy bárhol hibakóddal tér vissza egy parancs a szkriptben, azonnal álljon le a szkript. Képzeld el, hogy egy nem várt hiba történik és az egyik parancs nem fut le, de utána még 1000 sor kimenetet produkál a szkript, te pedig nem veszed észre a hibát, vagy egyszerűen teljesen hibás működést eredményez, ami miatt akár adatokat, fájlokat vesztesz el, mert másképp teljesülnek a feltételek. Ilyenkor tehát a szkript elején legalább a következő sor áll:
Tehát:
set -e
i=0
while (( i <= 10 )); do
echo -n "$i "
(( i++ ))
done
echo
A kimenet pedig egy nagy nulla:
Hm... Mi folyik itt? Nézzünk most egy dekrementálást és számoljunk 5-től mínusz 5-ig.
set -e
i=5
while (( i >= -5 )); do
echo -n "$i "
(( i-- ))
done
echo
A kimenet pedig:
A nulla tehát valami mágikus hatással bír és a szkript azonnal leáll aset -e
használata mellett. A mágikus hatás egyszerű magyarázata, hogy az aritmetikai műveleteknél, ha az eredmény nulla, az egyúttal hibakódot is jelent. Nézzük például a következő szkriptet:
i=5
while (( i >= -5 )); do
echo -n "i: $i, "
(( i-- ))
echo "code: $?"
done
A kimeneten látszik, hogy a 0 értéknél a hibakód 1-es.
i: 4, code: 0
i: 3, code: 0
i: 2, code: 0
i: 1, code: 0
i: 0, code: 1
i: -1, code: 0
i: -2, code: 0
i: -3, code: 0
i: -4, code: 0
i: -5, code: 0
"Hát ennek meg mi értelme?" - teheted fel a kérdést. Először én is gondolkodtam, de nézzünk még egy példát, ahol egyszerűen csak 6 alkalommal szeretnék lefuttatni egy utasítást:
set -e
echo "start"
echo
i=5
while echo -n "$i " && (( i-- )); do :; done
echo
echo
echo "end"
A kimeneten látszik, hogy hiába a "set -e
", a ciklus rendben lefut és az utána levő sorok is. Ciklusban vagy feltételben ugyanis a hibakódok csak a ciklus leállását jelentik, tehát használhatók arra az aritmetikai műveletek, hogy ciklust vezérelj velük.
5 4 3 2 1 0
end
Ha viszont nem ciklusfeltételként használod az értéknövelést, csökkentést, akkor azt kell elérni, hogy
- vagy ne legyen az aritmetikai műveletek eredménye nulla
- vagy gondoskodsz róla, hogy az aritmetikai műveletet egy olyan kifejezés részeként használd, ami összességében sosem adhat hibát
Az első példára az első megoldás is tökéletes, hiszen tényleg csak egy inkrementálásról van szó, és nyugodtan kezdhetem a 0 kezdőérték helyett 1-gyel a ciklust a ciklus törzsében korrigálva használatkor az értéket, vagy egyszerűen i++
helyett ++i
módon növelem az értéket, tehát még az aritmetikai művelet kiértékelése előtt történik a változó módosítása.
set -e
i=0
while (( i <= 10 )); do
echo -n "$i "
(( ++i ))
done
echo
Ez viszont már nem jó bonyolultabb műveletek esetén, pláne nem akkor, ha a nulla érték egy valóban érvényes, várt és kívánt érték. A második megoldás viszont már minden helyzetben alkalmazható és nem is sokkal hosszabb. A true
paranccsal és a ||
logikai operátorral kiegészítve az értéknövelést a teljes kifejezés mindenképpen hibamentes lesz:
set -e
i=0
while (( i <= 10 )); do
echo -n "$i "
(( i++ )) || true
done
echo
Most már hátra lehet dőlni, a kimenet pont olyan, amilyennek lennie kell:
Ha érdekel még hasonló téma, dobj egy like-ot és nézd meg a többi Bash-ről szóló cikket is: Bash