Komentoriviohjelmointi Bash eli Bourne-Again SHell komentotulkissa

Tekijä: Jaakko Kajaste, jkajaste@cs.stadia.fi

16.2.2002


1. Perusteet

2. Kommentit

3. Muuttujat

4. Uudelleenohjaus

5. Putket

6. Inputin lukeminen komentoriviltä

7. Funktiot

8. Lainausmerkit

9. Kontrollirakenteet

10. Argumenttien käyttö

11. Vertailut

12. Aritmetiikka

13. Trappaus

14. Paluuarvot

15. Komennot

16. Käytetyt lähteet

17. Lisätietoa aiheesta



1. Perusteet

Tässä dokumentissä käsitellään komentoriviohjelmointia. Komentotulkkina käytetään Bashia eli Bourne-Again SHelliä. Shell-skriptien avulla on kätevä automatisoida usein suoritettavia monimutkaisia ja miksei yksinkertaisiakin tehtäviä. Skriptien ymmärtäminen auttaa myös ymmärtämään Linux-järjestelmien toimintaa, koska monet Linuxin ohjelmat ovat erilaisia skriptejä. Skriptit sopivat parhaiten pienten tehtävien hoitamiseen. Shell skriptien kirjoittamiseen/ymmärtämiseen vaaditaan Linuxin peruskomentojen hallintaa, koska skripteissä käytetään näitä työkaluja hyväksi. Kuten monissa muissakin ohjelmointioppaissa, niin myös tässä tutustutaan ensimmäisenä Hello World-ohjelmaan. Tämä esimerkkiskripti tulostaa ruudulle tekstin "Hello World":

#!/bin/bash
echo "Hello World"
Skriptin ensimmäinen rivi keroo missä komentotulkissa skripti suoritetaan ja mistä hakemistosta komentotulkki löytyy. Bash ei välttämättä aina sijaitse /bin-hakemistossa, joten tarvittaessa sen sijainnin voi tarkistaa ainakin which-komennon avulla kirjoittamalla komentoriville:
which bash

2. Kommentit

Kommenttien avulla voidaan nimensä mukaisesti kommentoida ohjelman toimintaa. Kommenttien avulla koodista saadaan paljon luettavampaa ja näin ohjelman koodia tutkivalle ulkopuoliselle henkilölle selviää helpommin mitä ohjelma tekee. Kommentit eivät vaikuta milläänlailla ohjelman toimintaan. Ohjelman kommenttirivit alkavat "#"-merkillä. Skriptin ensimmäinen rivi (#!/bin/bash) ei kuitenkaan ole kommenttirivi vaikka se alkaa "#"-merkillä. Tässä on esimerkki kommentoidusta ohjelmasta:

#!/bin/bash
# tämä ohjelma tulostaa luvut 1-10
for i in 1 2 3 4 5 6 7 8 9 10;
do
	echo $i
done

3. Muuttujat

Muutttujia käytetään tiedon tallennuspaikkoina. Muuttujilla ei ole komentoriviohjelmoinnissa tietotyyppiä. Muuttujaan voidaan tallentaa numero, kirjain tai merkkijono. Tässä on pieni esimerkki muuttujan käytöstä ohjelmassa:

#!/bin/bash
luku=10
echo "Muuttujan luku arvo on $luku"
Ohjelmassa luku-muuttujalle annetaan arvo 10, jonka jälkeen tulostuu teksti "Muuttujan luku arvo on 10". Muuttujia määriteltäessä ei muuttujan nimen, "="-merkin ja muutujan arvon väliin saa jättää tyhjiä välejä. Yllä olevasta esimerkistä huomataan, että määriteltyä muuttujaa käytettäessä muuttujan nimen eteen laitetaan "$"-merkki.

3.1 Paikalliset muuttujat

Paikallinen muuttuja voidaan luoda käyttämällä avainsanaa local. Esimerkki tästä:

#!/bin/bash
HELLO=Hello
funktion hello {
	local HELLO=World
	echo $HELLO
}
echo $HELLO
hello
echo $HELLO
Ohjelmasta huomataan, että muuttuja HELLO ja paikallinen muuttuja HELLO eivät vaikuta toisiinsa millään tavalla.

3.2 Ympäristömuuttujat

Ympäristömuuttujat ovat järjestelmän muuttujia, joita voidaan käyttää skripteissä hyväksi. Alla on esimerkki SHELL-ympäristömuuttujan käytöstä. Ohjelmassa tulostetaan SHELL-muuttujan sisältämä käyttäjän oletus shell:

#!/bin/bash
echo $SHELL

3.3 Sisäänrakennetut muuttujat

Komentorivillä annetut parametrit talletetaan automaattisesti valmiiksi määriteltyihin muuttujiin, joita voidaan käyttää ohjelmassa.

Alla on listattuna muuttujien nimet ja kunkin muuttujan sisältämä tieto:

$0	Tähän muuttujaan tallennetaan suoritettavan skriptin nimi.
$1-$9	Näihin muuttujiin tallennetaan ohjelmalle annetut parametrit järjestyksessä.
$?	Tähän muuttujaan tallennetaan viimeisimmän suoritetun ohjelman exit arvo.
$*	Tähän muuttujaan tallennetaan kaikki ohjelmalle annetut argumentit ($1 $2 ...).
$@	Tähän muuttujaan tallennetaan kaikki ohjelmalle annetut argumentit ("$1" "$2" ...).
$#	Tähän muuttujaan tallennetaan ohjelmalle annettujen argumenttien määrä.

4. Uudelleenohjaus

Uudelleenohjauksen avulla voidaan tuloste ohjata oletuskohteen sijaan muualle, esimerkiksi tiedostoon, joka tapahtuu ">"-operaattorin avulla. Oletuskohteet ovat:

Oletus tulostus eli stdout (standard output) on näyttö (jota merkitään numerolla 1).
Oletus syöte eli stdin (standard input) on näppäimistö.
Oltus virhe eli stderr (standard error) on näyttö (jota merkitään numerolla 2).

Alla on esitelty neljä esimerkki tapausta siitä mitä uudelleeohjauksen avulla voidaan tehdä:

4.1 Ohjataan stdout tiedostoon

ls -l > ls-l.txt
Tämä luo ls-l.txt nimisen tiedoston, jonka sisällöksi tulee "ls -l"-komennon suorituksen tulos.

4.2 Ohjataan stderr tiedostoon

cat teksti 2> error
Ohjelma tulostaa teksti nimisen tiedoston näytölle, jos tiedostoa ei ole olemassa, tästä aiheutuva virheilmoitus ohjataan error nimiseen tiedostoon.

4.3 Ohjataan stdout stderr:iin

ls -l 1>&2
Hakemiston listaus eli "ls -l"-komennon suorituksen tulos ohjataan samaan paikkaan kuin stderr.

4.4 Ohjataan stderr stdout:iin

cat teksti 2>&1
Mahdollinen stderr ohjataan stdout:iin.

Tiedostoon uudelleenojatessa ">"-merkkiä käytettäessä tiedoston vanha sisältö tuhotaan. ">>"-merkkiä käytettäessä tiedoston sisältöä ei tuhota, vaan teksti lisätään vanhan tekstin perään.

5. Putket

Putkituksen avulla voidaan toisen ohjelman tuloste ohjata toisen ohjelman syötteeksi. Putkitus saadaan aikaiseksi "|"-operaattoria käyttäen. Esimerkki tästä:

ls -l | grep .cpp
Esimerkissä hakemistolistauksen tuloste ohjataan grep komennolle, joka etsii tulosteesta kaikki rivit, jossa esiintyy pääte ".cpp" ja tulostaa nämä rivit näytölle.

6. Inputin lukeminen komentoriviltä

Skriptien avulla voidaan tehdä myös ohjelmia, joilla voidaan kesken ohjelman suorituksen lukea käyttäjän antamia syötteitä. Tämä voidaan tehdä read-käskyn avulla. Esimerkki read:in käytöstä:

#!/bin/bash
# luetaan käyttäjän nimi ja tervehditään käyttäjää
echo -n "Mikä on nimesi: "
read nimi
# tarkistetaan syöttikö käyttäjä nimen:
if [ -z "$nimi" ];
then
	echo "Et kertonut nimeäsi."
	exit
fi
echo "Terve $nimi!"
Käyttäjän painaessa enter-näppäintä ilman nimen syöttöä ohjelma tulostaa "Et kertonut nimeäsi.", ja ohjelman suoritus lopetetaan. Jos käyttäjä syöttää esim. nimen Matti, ohjelma tervehtii käyttäjää näin: "Terve Matti!". Syötteen lukemista voitaisiin käyttää myös esimerkiksi ohjelmassa, jossa käyttäjän syötettämiä tietoja vietäisiin tietokantaan.

7. Funktiot

Funktioiden käytön avulla saadaan skripteistä paljon helpommin ylläpidettäviä, koska ohjelma saadaan jaettua pienempii osiin. Funktioille voidaan viedä parametrejä, ja funktiolla voi olla paluuarvo. Funktio pitää olla skriptissä määriteltynä ennen varsinaista kutsumista.

Funktio määrittellään näin:

funktio1(){
	komentoja
}

Funktiota kutsutaan näin:
funktio1

Funktion määrittelyn eteen voidaan havainnollisuuden lisäämiseksi kirjoittaa function-avainsana:
function funtio1(){
	komentoja
}

Funktiolle voidaan myös myös määritellä parametrejä:
funktio2(parametri1,parametri2...parametriN){
	komentoja
)

Parametrejä sisältävää funktiota kutsutaan näin:
funktio2 parametri1 parametri2... parametriN

Esimerkki funktion käytöstä:
#!/bin/bash

# funktio uuden käyttäjän luomiseen
luo_kayttaja()
{
	echo "Luodaan uusi käyttäjä..."
	sleep 2
	adduser
}

echo "1. Luo käyttäjä"
echo "2. Exit"
echo "Anna valintasi: "
read valinta

case $valinta in
	1) luo_kayttaja # kutsutaan luo_kayttaja()-funktiota
	;;
	*) exit
	;;
esac
Tämän skriptin käyttämiseen tarvitaan rootin oikeudet adduser-komennon käytön takia.

8. Lainausmerkit

Lainausmerkkejä on kolmenlaisia, joilla on eri merkitys skriptejä kirjoitettaessa.

8.1 "-lainausmerkki

Käytetään, jos halutaan esimerkiksi määritellä useasta sanasta koostuva merkkijono. Esimerkki tästä:

mkdir hello world
Tämän käskyn suorittaminen luo sekä hakemiston "hello", että hakemiston "world". Jos kuitenkin halutaan luoda vaan yksi hakemisto, kirjoitetaan:
mkdir "hello world"
Ensimmäisessä esimerkissä hello ja world olivat kaksi omaa argumenttiä. Lainausmerkkien avulla niistä saadaan tehtyä haluttu yksi argumentti, joka koostuu kahdesta sanasta. Näin saadaan luotua hakemisto nimeltä "hello world". Tässä haluaisin kuitenkin korostaa, että tämä oli vain havainnollistava esimerkki ja Linux-maailmassa on suositeltavampaa käyttää tiedoston niminä yhdestä sanasta koostuvia nimiä. Esimerkin hekemiston nimen suositeltavampi muoto olisi esimerkiksi "hello_world".

8.2 '-lainausmerkki

Käytetään yleensä muuttujien kanssa. Esimerkki tästä:

#!/bin/bash
x=5 # alustetaan x:n arvoksi 5
echo "x on $x"
echo 'x on $x'
Ensimmäinen echo tulostaa "x on 5" ja toinen "x on $x". Myös tätä käytettäessä voidaan luoda edellä esiteltyjä kahdesta sanasta koostuvia tiedoston nimiä.

8.3 `-lainausmerkki

Tämä lainausmerkki eroaa paljon kahdesta edellä esitellystä. Tässä on esimerkki kyseisen lainausmerkin käytöstä:

#!/bin/bash
echo "Käyttäjä tunnukseni on `whoami`"
Tämä ohjelma tulostaa tekstin "Käyttäjä tunnukseni on Matti".

Tässä on esimerkki siitä, miten "$( )" saadaan korvattua lainausmerkeillä:
x=$(expr $x + 1)
Sama lause lainausmerkkejä käyttäen:
x=`expr $x + 1`

9. Kontrollirakenteet

Kontrollirakenteiden avulla saadaan lisättyä ohjelmaan rakenteellisuutta. Tässä on käyty läpi eri ehto- ja toistolauseita.

9.1 Ehtolauseet

Ehtolauseiden avulla voidaan päättä suoritetaanko joku toimenpide vai ei. Tärkeä tehtävä joka niiden avulla saadaan hoidettua on virheiden käsittely. Tässä on pieni esimerkki, jossa ehtorakenteen käytöstä olisi hyötyä:

#!/bin/bash
cp /etc/foo .
echo "Kopiointi suoritettu"
Ohjelma kopioi "/etc/foo"-tiedoston nykyhakemistoon ja tulostaa tekstin "Kopiointi suoritettu". Ohjelmassa ei oteta huomioon onko tiedosto "/etc/foo" olemassa. Jos tiedosto ei ole olemassa järjestelmä tulostaa virheilmoituksen. Ohjelmaa kirjoittaessa kannattaisi huomioida, että tiedostoa "/etc/foo" ei välttämättä ole olemassa. Tämä saadaan hoidettua ehtorakenteen avulla. Tähän palataan seuraavassa esimerkissä. Useat skripteissä käytetyt komennot ovat järjestelmässä olevia käskyjä, joita voidaan käyttää ilman skriptejäkin. Ehtorakenteet taas ovat skriptien ominaisuuksia, joita ei voida normaalien käskyjen tapaisesti käyttää. Tässä on edellinen ohjelma uudelleenkirjoitettuna:
#!/bin/bash
if test -f /etc/foo
then
	# tiedosto on olemassa, joten suoritetaan kopiointi
	# ja ilmoitetaan käyttäjälle onnistuneesta kopioinnista.
	cp /etc/foo .
	echo "Kopiointi suoritettu."
else
	# tiedostoa ei ole olemassa, joten ilmoitetaan käyttäjälle
	# epäonnistuneesta kopioinnista ja lopetetaan ohjelman suoritus.
	echo "Tiedostoa ei löydy."
	exit
fi
Ohjelmassa "if test" testaa onko "/etc/foo"-tiedostoa olemassa ja "-f" testaa onko "/etc/foo" tiedosto, jos se on olemassa ja se on tiedosto kopiointi suoritetaan ja annetaan ilmoitus onnistuneesta kopioinnista, muuten tulostetaan virheilmoitus. Kappaleessa 11. on käsitelty lisää kontrollirakenteiden ehtoihin liittyviä optioita. Edellä käytetylle syntaksille on myös vaihtoehtoinen tapa määritellä sama asia. Edellä käytetty tapa oli:
if test -f /etc/foo
then
Sama voidaan tehdä myös näin:
if [ -f /etc/foo ];
then
Jälkimmäistä tapaa käytettettäessä hakasulkeiden yhteydessä välilyönnit pitää kirjoittaa juuri kyseisellä tavalla. Seuraavaksi tässä on luettelon muodossa käyty läpi olemassa olevat ehtorakenteet:

9.1.1 If...then

if [ lauseke ]
then
	komentoja
fi

9.1.2 If...then...else

if [ lauseke ]
then
	komentoja
else
	komentoja
fi

9.1.3 If...then...else if...else

if [ lauseke1 ]
then
	komentoja
elif [ lauseke2 ]
then
	komentoja
else
	komentoja
fi

9.1.4 Case...in...done

case merkkijono in
	merkkijono1)
		komentoja;;
	merkkijono2)
		komentoja;;
	*)
		komentoja;;
esac
Merkkijonoa verrataan merkkijono1:seen ja sen jälkeen merkkijono2:seen. Jos jompi kumpi näistä on sama kuin merkkijono, niin sen valitun vaihtoehdon jälkeiset komennot suoritetaan. Jos samaa merkkijonoa ei löydy, suoritetaan * jälkeen olevat komennot.

Esimerkki casen käytöstä:
#!/bin/bash
x=5 # alustetaan x 5:ksi
# katsotaan mikä on x:n arvo:
case $x in
	0) echo "x:n arvo on 0."
	;;
	5) echo "x:n arvo on 5."
	;;
	9) echo "x:n arvo on 9."
	;;
	*) echo "Tunnistamaton arvo."
esac
Ohjelmassa katsotaan onko x:n arvo 0, 5 tai 9. Jos x:n arvo on joku edellä mainituista, luku ilmoitetaan käyttäjälle. Jos arvoa ei tunnisteta tulostetaan teksti "Tuntematon arvo."

Sama toiminnallisuus saadaan aikaan myös if-rakennetta käyttäen:
#!/bin/bash
x=5 # alustetaan x 5:ksi
if [ "$x" -eq 0 ]; then
	echo "x:n arvo on 0."
elif [ "$x" -eq 5 ]; then
	echo "x:n arvo on 5."
elif [ "$x" -eq 9 ]; then
	echo "x:n arvo on 9."
else
	echo "Tunnistamaton arvo."
fi

9.2 Toistolauseet

9.2.1 For...in...do...done

for muuttuja in lista
do
	komentoja
done
Silmukka suoritetaan listassa olevien alkioiden lukumäärää vastaava määrä kertoja. Muuttuja saa arvokseen listan sen hetkisen alkion arvon. Esimerkki tämän rakenteen käytöstä:
#!/bin/bash
for piste in 1 2 3 4 5 6 7 8 9 10;
do
	echo "."
done
Ohjelma tulostaa kymmenen pistettä ruudulle

Hyödyllisempi esimerkki:
#!/bin/bash
for tiedosto in *;
do
	echo "Lisätään .html loppu tiedostoon $tiedosto"
	mv $tiedosto $tiedosto.html
	sleep 1
done
Tämä ohjelma lisää hakemiston kaikkien tiedostojen perään päätteen ".html". Uudelleen nimeäminen suoritetaan mv-komennon avulla.

9.2.2 While...do...done

While-silmukkaa suoritetaan niin kauan kun ehto on tosi. Suoritus lopetetaan false arvoon tai break:iin. While-rakenne:

while [ lauseke ]
do
	komentoja
done
Esimerkki while rakenteen käytöstä:
#!/bin/bash
x=0; # annetaan x:lle arvo 0
while [ "$x" -le 10 ];
do
	echo "x:n arvo on $x"
	# kasvatetaan x:n arvoa
	x=$(expr $x + 1)
	sleep 1
done
Ohjelmassa ehto "-le" testaa onko x:n arvo pienempi tai yhtäsuuri kuin 10. Ohjelma tulostaa x:n arvon ja kasvattaa sitä yhdellä. Tämä suoritetaan kunnes ehto on epätosi.

9.2.3 Until...do...done

Until-rakenne:

until [ lauseke ]
do
	komentoja
done
Until-rakenne muistuttaa paljon while-rakennetta. Sitä suoritetaan niin kauan kun ehdon arvo on tosi.

Esimerkki rakenteen käytöstä:
#!/bin/bash
x=0;
until [ "$x" -ge 10 ];
then
	echo "x:n arvo on $x"
	x=$(expr $x + 1)
	sleep 1
done
Silmukkaa suoritetaan, kunnes x arvo on suurempi tai yhtä suuri kuin 10. Kun x:n arvo on 10 ja vertailu suoritetaan, vertailulohkon sisällä olevia komentoja ei enää suoriteta, joten viimeisin x:n arvo joka tulostetaan on 9.

9.3 AND & OR

Tässä on käsitelty AND:in ja OR:in käyttöä kontrollirakenteissa.

9.3.1 AND

AND:in ehtolause on seuraava:

ehto1 && ehto2

Ensin tarkistetaan vasemman puolinen ehto, jos se on tosi, tarkistetaan oikean puoleinen ehtokin. Jos oikean puoleinenkin ehto on tosi, niitä seuraavat komennot suoritetaan. Jos vasemmanpuoleinen ehto ei ole tosi, oikeanpuoleista ehtoa ei tutkita. Esimerkki AND:in käytöstä:

#!/bin/bash
x=5
y=10
if [ "$x" -eq 5 ] && [ "$y" -eq 10 ];
then
	echo "Molemmat ehdot saivat arvon true."
else
	echo "Ainakin toinen ehdoista saa arvon false."
fi
AND:in käyttö voidaan korvata seuraavan esimerkin mukaisesti kahdella if-lauseella:
#!/bin/bash
x=5
y=10
if [ "$x" -eq 5 ];
then
	if [ "$y" -eq 10 ];
	then
		echo "Molemmat ehdot saivat arvon true."
	else
		echo "Toinen ehdoista sai arvon false."
fi
AND:in käyttö on kuitenkin selkeämpää ja näin ollen suositeltavampaa, kuin kahden prättäkkäisen if-lauseen käyttö.

9.3.2 OR

OR:ia käytettäessä vasemman ehdon ollessa false tutkitaan silti oikeanpuoleinen ehto. Jos se on true niin komennot suoritetaan. Eli OR:ia käytettäessä riittää, että toinen ehto on tosi. Syntaksi on seuraava:

ehto1 || ehto2

Esimerkki OR:in käytöstä:

#!/bin/bash
x=5
y=10
if [ "$x" -eq 5 ] || [ "$y" -eq 20 ];
then
	echo "Ainakin toinen ehto saa arvon true."
else
	echo "Kumpikaan ehdo ei ole true."
fi

10. Argumettien käyttö

Luvussa 3. on listattuna mitä kaikkia eri tietoja skriptille annetuista argumenteistä saadaan ohjelmassa käyttöön. Esimerkki argumenttien käytöstä:

#!/bin/bash
# ohjelma tulostaa ensimmäisen argumentin
# tutkitaan annettiinko ohjelmalle parametriä:
if [ "$#" -ne 1 ];
then
	echo "Virhe!"
fi

echo "Argumentti on $1"
Eli ohjelmalle pitää antaa vain yksi argumetti, eikä yhtään enempää eikä vähempää. Jos toimitaan virheellisesti ohjelma tulostaa tekstin "Virhe!". Muuten ohjelma tulostaa tekstin "Argumentti on testi", missä sana testi on juuri kyseinen ohjelmalle annettu argumentti.

11. Vertailut

Tässä on käyty läpi listauksen muodossa se millä tavalla esimerkiksi muuttujien arvoja voidaan vertailla kontrollirakenteita käytettäessä.

11.1 Numeroiden vertailu

luku1 -eq luku2		paluuarvo on true, jos luku1 == luku2
luku1 -ge luku2		paluuarvo on true, jos luku1 >= luku2
luku1 -gt luku2		paluuarvo on true, jos luku1 > luku2
luku1 -le luku2		paluuarvo on true, jos luku1 <= luku2
luku1 -lt luku2		paluuarvo on true, jos luku1 < luku2
luku1 -ne luku2		paluuarvo on true, jos luku1 != luku2

11.2 Merkkijonojen vertailu

merkkijono1 = merkkijono2	paluuarvo on true, jos merkkijono1 = merkkijono2
merkkijono1 != merkkijono2	paluuarvo on true, jos merkkijono1 != merkkijono2
merkkijono			paluuarvo on true, jos merkkijono ei ole null
-n merkkijono			paluuarvo on true, jos merkkijonon pituus on suurempi kuin nolla
-z merkkijono			paluuarvo on true, jos merkkijonon pituus on nolla

11.3 Tiedostojen vertailu

-d tiedosto	paluuarvo on true, jos tiedosto on hakemisto
-f tiedosto	paluuarvo on true, jos tiedosto on normaali tiedosto
-e tiedosto	paluuarvo on true, jos tiedosto on olemassa
-r tiedosto	paluuarvo on true, jos tiedostoon on lukuoikeus
-w tiedosto	paluuarvo on true, jos tiedostoon on kirjoitusoikeus
-x tiedosto	paluuarvo on true, jos tiedostoon on suoritusoikeus
-s tiedosto	paluuarvo on true, jos tiedoston koko ei ole nolla
-g tiedosto	paluuarvo on true, jos tiedostolla on SGID oikeudet
-u tiedosto	paluuarvo on true, jos tiedostolla on SUID oikeudet

11.4 Lausekkeiden vertailu

!lauseke		paluuarvo on true, jos lauseke ei ole true
lauseke1 -a lauseke2	paluuarvo on true, jos sekä lauseke1 että lauseke2 saavat arvon true (and)
lauseke1 -o lauseke2	paluuarvo on true, jos joko lauseke1 tai lauseke2 saa arvon true (or)

12. Aritmetiikka

Skripteissä voidaan käyttää hyväksi laskennallisia lausekkeita. Laskutoimituksissa voidaan käyttää kaikkia perustoimintoja: +, -, *, / ja %. Tässä on esimerkki, jossa näiden käyttöä on havainnollistettu:

#!/bin/bash
x=10 # alustetaan x:n arvoksi 10
y=5 # alustetaan y:n arvoksi 5

summa=$(($x + $y))
erotus=$(($x - $y))
tulo=$(($x * $y))
jako=$(($x / $y))
jakojaannos=$(($x % $y))

# tulostetaan vastaukset:
echo "Summa: $summa"
echo "Erotus: $erotus"
echo "Tulo: $tulo"
echo "Jako: $jako"
echo "Jakojäännös: $jakojaannos"
Esimerkissä käytetyn syntaksin sijaan ( summa=$(($x + $y)) ) olisi voitu käyttää myös vaihtoehtoisesti jompaa kumpaa näistä:
summa=$(expr $x + $y)
tai
summa=`expr $x + $y`

13. Trappaus

Niin sanottu trappaus saadaan aikaiseksi trap-komennon avulla. Tämän avulla esimerkiksi CTRL-C-painamisesta aiheutuva keskeytys, joka normaalisti keskeyttää ohjelman suorituksen, saadaan käsiteltyä hallitusti. Trapin avulla keskeytys saadaan otettua kiinni, jolloin käyttäjältä voidaan kysyä esimerkiksi haluaako hän varmasti lopettaa ohjelman suorituksen. Syntaksi on seuraava:

trap toimenpide signaali
Määritelty toimenpide suoritetaan kun signaali aktivoidaan. Esimerkki tämän käytöstä:
#!/bin/bash
# harjoitellaan trap käskyn käyttöä

# CTRL-C painaminen johtaa toimenpide()-funkition suoritukseen
trap toimenpide INT

# funktio toimenpide() tulostaa viestin
toimenpide()
{
	echo "Eipä lopeteta vielä."
	sleep 3
}

# suoritetaan silmukka kymmenen kertaa
for i in 1 2 3 4 5 6 7 8 9 10;
do
	echo "$i"
	sleep 1
done
Jos ohjelman suorituksen aikana painetaan CTRL-C näppäimiä aiheutuu keskeytys, joka johtaa toimenpide( )-funktion suoritukseen. Näin käyttäjän painama CTRL-C saadaan käsiteltyä hallitummin. Trap voidaan määritellä myös toisella tavalla. Tässä pari esimerkkiä:
# suoritetaan oletuksena oleva toimenpide eli lopetetaan
# skriptin suoritus CTRL-C-näppäimiä painettaessa
trap - INT

# CTRL-C ei vaikuta mitenkään ohjelman toimintaan,
# vaan suoritusta jatketaan normaalisti
trap '' INT

14. Paluuarvot

Ohjelman paluuarvo talletetaan aumaattisesti muuttujaan $?. Paluuarvo 0 tarkoittaa onnistunutta exit:iä. Jos exit arvo on suurempi kuin 0, niin se tarkoittaa virhettä. Esimerkki tästä:

#!/bin/bash
if [ -f "/etc/passwd" ];
then
	echo "/etc/passwd tiedosto on olemassa."
	exit 0
else
	echo "/etc/passwd tiedostoa ei ole olemassa."
	exit 1
fi
Tässä esimerkissä määriteltiin itse paluuarvot. Myös funktiot voivat palauttaa paluuarvon. Se saadaan aikaiseksi return komennolla. return:in parametriksi annetaan yksi numero argumentiksi. Muuten sen toimii exit:in tapaan, paitsi että sitä käytetään funktioiden kanssa. Esimerkki tästä:
#!/bin/bash

tutki_passwd()
{
	# katsoo onko /etc/passwd olemassa:
	if [ -f "/etc/passwd" ];
	then
		echo "/etc/passwd tiedosto on olemassa."
		# löytyy, paluuarvoksi 0
		return 0
	else
		echo "/etc/passwd tiedostoa ei ole olemassa."
		# ei löydy, paluuarvoksi 1
		return 1
	fi
}

# otetaan tutki_passwd()-funktion paluuarvo talteen
tutki=tutki_passwd
# tarkistetaan lötykö tiedostoa:
if [ "$tutki" -eq 0 ];
then
	echo "Tiedosto löytyi."
	exit 0
else
	echo "Tiedostoa ei löytynyt."
	exit 1
fi
Ohjelmassa funktion tutki_passwd( ) paluuarvo laitetaan tutki-muuttujan arvoksi. Jos tiedosto löytyy paluuarvo on 0, jos sitä ei löydy paluuarvoksi tulee 1. Lopuksi käyttäjälle tulostetaan tieto tiedoston löytymisestä ja poistutaan 0:lla jos se löytyi, ja 1:llä jos ei löytynyt.

15. Komennot

Tässä on listattuna joitain tärkeimpiä komennoja, joita tarvitaan skriptejä kirjoitettaessa ja komentoriviä käytettäessä. Lista ei todellakaan ole kattava, mutta näiden avulla pääsee jo hyvään alkuun. Komentojen perään on lisätty lyhyt selvitys siitä mitä komento tekee.

bc	laskin ohjelma
cat	tiedoston sisällön tulostus
cd	hakemistosta toiseen siityminen tapahtuu tämän käskyn avulla
chmod	muuttaa tiedoston oikeuksia
echo	tulostaa tekstiä näytölle
grep	tulostaa ehdot täyttävät rivit syötteestä
less	tulostaa tekstiä sivu kerrallaan
ls	tulostaa hakemiston sisällön
mkdir	luo hakemiston
more	ulostaa tekstiä rivi kerralaan
rm	poistaa tiedostoja
rmdir	tuhoaa hakemiston
sed	ohjelma tekstin muokkaamiseen
sleep	"nukutaan" eli ollaan tekemättä mitään määritelty aika sekunteissa
sort	lajittelee tiedoston rivit
wc	laskee rivit, sanat ja tavut tiedostosta

16. Käytetyt lähteet

Bash Programming Cheat Sheet
Introduction to bash shell scripting
BASH Programming - Introduction HOW-TO

17. Lisätietoa aiheesta

Skriptaus UNIX:eissa
Bourne-shellin ohjelmointi
Unix ja shell-ohjelmointi
Advanced Bash-Scripting Guide
Bash Reference Manual
The GNU Bourne-Again SHell
Bash man page
Bash Prompt HOWTO
Pieni Linux-kirjanen
Bourne/Bash Shell: Programmin Introduction