Egész szám növelése, csökkentése Bash ciklusban

Gondolkodó ember árny a piyabay.com-ról + hozzáadott gondolat

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.

#!/bin/bash

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.

0 1 2 3 4 5 6 7 8 9 10

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:

set -e

Tehát:

#!/bin/bash

set -e

i=0
while (( i <= 10 )); do
  echo -n "$i "
  (( i++ ))
done

echo

A kimenet pedig egy nagy nulla:

0

Hm... Mi folyik itt? Nézzünk most egy dekrementálást és számoljunk 5-től mínusz 5-ig.

#!/bin/bash

set -e

i=5
while (( i >= -5 )); do
  echo -n "$i "
  (( i-- ))
done

echo

A kimenet pedig:

5 4 3 2 1 0

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:

#!/bin/bash

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: 5, code: 0
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:

#!/bin/bash

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.

start

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.

#!/bin/bash

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:

#!/bin/bash

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:

0 1 2 3 4 5 6 7 8 9 10

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

Megosztás/Mentés