Řídící konstrukce v shellu

Dnes si ukážeme podmínku if, a cykly for a while. Pokud jste již programovali v procedurálním jazyce, jistě vám tyto konstrukce nebudou neznámé. Jen je třeba si zvyknout na trošku odlišnou syntaxi.

Průběžně si také ukážeme několik pomocných příkazů - test, expr, seq


test

Příkaz, jehož aliasem je hranatá závorka - [ (pokud je test použitý takhle, musí mít jako poslední parametr opačnou hranatou závorku ]). Vrací true / false, ovšem pouze jako návratový kód. Má smysl ho tedy používat právě v podmínkách.

Nejdůležitější použití:

# FUNKCE SE SOUBORY
# Existuje soubor file?
test -e file
 
# Lze do souboru file zapisovat?
test -w file
 
# FUNKCE S ŘETĚZCI
# Je proměnná $A neprázdná?
test -n "$A"
 
# Je proměnná $A prázdná?
test -z "$A"
 
# FUNKCE S ČÍSLY
# Je $A stejná jako (equals) $B ?
test $A -eq $B
 
# Je $A menší než (lesser then) $B?
test $A -lt $B  
 
# Je $A menší nebo rovna (lesser or equal then) $B?
test $A -le $B
 
# Je $A větší než (greater then) $B?
test $A -gt $B
 
# Je $A větší nebo rovna (greater or equal then) $B?
test $A -ge $B

Více ve Wikipedii(en)

Použití v podmínce if:

if

Za if se píše příkaz, vracející návratový kód 0(true)/jiný (false). Může to být příkaz test, ale ne nutně - vlastně většina příkazů či programů onen návratový kód vrací dle kontextu (například cp … povedlo se či nepovedlo kopírování?).

Nejjednodušší:

if [příkaz podmínky]
then
  [příkazy k vykonání]
fi

Použití else = jinak:

if [příkaz podmínky]
then
  [udělej cosi]
else
  [udělej něco jiného]
fi  

Použití elif - další podmínky:

read num
if [ $num -eq 5 ]
then
  echo "Cislo je vetsi nez pet"
elif [ $num -lt 5 ]
  echo "Cislo je mensi nez pet"
else
  echo "Jina moznost"
fi         

Pozor:

  • Tam kde jsou odřádkování skutečně musí být odřádkování - nebo středník ;
  • nezapomeňte na fi na konci.

Příklady

if test $A -eq $B
 then
  echo "A je rovno B!"
 else
   echo "A se nerovná B."
 fi

 if [ $A -lt $B ]
 then
   echo "A je menší než B"
 elif [ $A -gt $B ]
   echo "A je větší než B"
 elif [ $A -eq $B ]
   echo "A je stejné jako B"
 else
 # Možná to nejsou čísla
   echo "Err"
 fi

Úloha:

Jak ve scriptu zkontrolovat, zda je parametr $1 číselný?


expr

expr je další užitečný příkaz. Slouží k aritmetice - k počítání s celými čísly.

Například tedy:

expr 5 + 5
expr 3 \* 2 

(Nezapomeňme, že hvězdička je metaznak shellu)

Každý člen výrazu musí být samostatný parametr - tedy oddělený od ostatních mezerou. Vypočítat pomocí expr výraz 5*3+8 lze tedy:

expr 5 \* 3 + 8

Lze použít (odescapované) závorky - pro změnu priority operací:

expr 5 \* \( 3 + 2 \)
#Vypíše 25
 
expr 5 \* 3 + 2
#Vypíše 17

expr lze samozřejmě jednodušše použít i k počítání s proměnnými. Musí být ale skutečně obsahovat čísla!

#sčítání parametrů
expr $1 + $2
 
#Zvýšení hodnoty proměnné
a=`expr $a + 1`
 
----
==== seq ====
Příkaz ''seq'' vypisuje číselnou řadu. Typicky se používá se dvěma parametry - prvním číslem a posledním - například
<code bash>
seq 1 5
#vypíše 1 2 3 4 5

Lze ale i změnit krok (navyšovat o deset a ne o jednu, nebo dokonce záporně) - se třemi parametry jako

seq PRVNÍ KROK POSLEDNÍ

seq 10 -2 1
#vypíše 10 8 6 4 2

read

read r přečte jednu řádku ze vstupu a uloží ji do proměnné r. Dá se použít například v interaktivní kalkulačce:

#!/bin/sh
echo "Zadej prvni cislo"
read a 
echo "Zadej druhe cislo"
read b
echo "Secteno je to `expr $a + $b`"

for

for promenna in seznam
do
  prikaz
done   

Přičemž seznam je jakkoliv dlouhá posloupnost řetězců (oddělených mezerou). Mohou to být čísla:

for a in 1 2 3 4
do
 expr $a * $a
done

Stejně tak to ale mohou být i slova:

for a in stul zidle lampa skrin
do
 echo $a je kus nabytku
done

Je tedy vidět, na co se nám hodí příkaz seq ?

Cyklus „pro všechna čísla od 1 do 100 vypiš jejich dvojnásobky“ napíšeme jako:

for a in `seq 1 100`
 do
 expr $a \* 2
done

----
===while===    
<code bash>
while podminka
do
  prikaz
done  

Cyklus while se opakuje, dokud je podmínka splněna. Je tedy potřeba zajistit, aby někdy splněna byla - jinak cyklus nikdy neskončí.

Podmínka ve while je to samé, jako podmínka v if. Můžeme tak třeba jednoduše nahradit for cyklus:

a=0
while [ $a -le 100 ]
 do
 echo $a
 a=`expr a + 1`
done

Nebo na čtení ze vstupu pomocí příkazu read

while read radek
 do 
 echo "$radek"
done
 
Nebo na čtení ze souboru:
<code bash>
while read radek
 do
 echo "$radek"
 done < soubor

(pozor na soubory které nekončí znakem nové řádky!)

Úloha:

Vytvořte script secti.sh, který sečte všechny svoje parametry (které jsou číselné). Tj. například

./secti.sh 1 4 5 12
22

Úloha

Script, který očísluje řádky vstupu / souboru. Tj ze souboru

ahoj
svete
jak se mas?

udělá:

1 ahoj
2 svete
3 jak se mas?
Nahoru