Komentoriviohjelmointi


Komentotulkin muuttujat, muuttujien määrittäminen ja arvon vaihtaminen, Kolmenlaisia lainausmerkkejä, Komentotiedostot, Komentotulkin määrittäminen itse komentotiedostossa, Komentoriviargumentit, Laskutoimituksia expr-apuohjelman avulla, test-ohjelma, Kontrollirakenteet, Ehtolause, for-toistolause, while-toistolause, Tapausrakenne case, Lukeminen päätteeltä

Tämän osan tarkoituksena on tutustuttaa Linuxin komentotulkkien komentokieleen. Esimerkkinä on käytetty Bourne-shell-komentotulkkia, koska tämä tulkki löytyy käytännössä jokaisesta Unix-järjestelmästä. Sen takia sillä tehdyt komentotiedostot toimivat varmuudella missä järjestelmässä tahansa. Lisäksi Linuxin oletuskomentotulkki BASH (Bourne Again SHell) on hyvin tämän kaltainen järjestelmä. Esimerkiksi komentotulkin muuttujat ovat hyvin samanlaiset.


Komentotulkin muuttujat

Komentotulkki käyttää useita muuttujia yksityiskohtien ohjaamiseen. Näiden arvot ovat yleensä käyttäjäkohtaisia ja sitä kautta ne mahdollistavat oman käyttäjäympäristön räätälöimisen omiin tarkoituksiin.

Muuttujat saat näkyville komentotulkin sisäisellä set-komennolla:

BASH=/bin/bash
BASH_ENV=/home/kuivanen/.bashrc
BASH_VERSION=1.14.7(1)
BOOT_IMAGE=linux
COLORTERM=gnome-terminal
COLUMNS=80
CONSOLE=/dev/console
DISPLAY=:0
EUID=500
GDMSESSION=Default
HISTFILE=/home/kuivanen/.bash_history
HISTFILESIZE=1000
HISTSIZE=1000
HOME=/home/kuivanen
HOSTNAME=kuivi49h8
HOSTTYPE=i386
IFS= 	

INIT_VERSION=sysvinit-2.74
INPUTRC=/etc/inputrc
KDEDIR=/usr
LINES=40
LOGNAME=kuivanen
MAIL=/var/spool/mail/kuivanen
MAILCHECK=60
OLDPWD=/home/kuivanen
OPTERR=1
OPTIND=1
OSTYPE=Linux
PATH=/usr/bin:/usr/local/bin:/bin:/usr/X11R6/bin:/home/kuivanen/bin:
PPID=659
PREVLEVEL=N
PS1=[\u@\h \W]\$ 
PS2=> 
PS4=+ 
PWD=/home/kuivanen/bin
RUNLEVEL=5
SESSION_MANAGER=local/kuivi49h8:/tmp/.ICE-unix/556,tcp/kuivi49h8:1025
SHELL=/bin/bash
SHLVL=3
TERM=xterm
UID=500
USER=kuivanen
USERNAME=
WINDOWID=79691782
XAUTHORITY=/home/kuivanen/.Xauthority
_=bin

Mainittakoon muuttujista seuraavat:

  • HOME - käyttäjän kotihakemisto
  • PATH - hakupolku. Huomaa bin-hakemisto käyttäjän kotihakemistossa (/home/kuivanen/bin). Laita komentotiedostosi tähän hakemistoon.
  • MAIL - käyttäjän postilaatikko
  • PS1 - kehote
  • PS2 - toinen kehote, joka tulee näytölle, jos komento jää jostain syystä kesken (esim. puuttuu lopusta lainausmerkki tms...)
  • USER - käyttäjän käyttäjätunnus

Jos halutaan käyttää kenties tarkempaa ilmaisua kuin "komentotulkin muuttujat", voisi myös puhua "ympäristömuuttujista", vaikuttavathän nämä muuttujat käyttäjän komentotulkin ympäristöön.


Muuttujien määrittäminen ja arvon vaihtaminen

Muuttuja määritellään seuraavasti:

muuttujan_nimi=muuttujan_arvo

Esimerkiksi:

koe=Morjens

Näin olemme luoneet koe-nimisen muuttujan. Muuttujan arvoon voidaan viitata laittamalla nimen eteen $-merkki:

echo $koe

Tulostaa koe-nimisen muuttujan sisällön. Samalla tavoin voi myös tulostaa komentotulkin ympäristömuuttujia:

echo $SHELL

Tulostaa ruudulle komentotulkkisi nimen.

Huomattavaa on, etteivät Linuxin (Unixin) muuttujat ole yleensä globaaleja. Näin ollen jos muuttuja on määritelty jossakin komentotulkissa ja komentotiedostohan lähtökohtaisesti käynnistää suoritustaan varten uuden komentotulkin, tällöin ylemmällä tasolla määritelty muuttuja ei olekaan enää olemassa tässä uudessa komentotulkissa. Poikkeuksena ovat ns. ympäristömuuttujat, jotka voidaan export-lauseella sijoittaa ympäristöön.


Kolmenlaisia lainausmerkkejä...

Linuxissa (kuten unixissa) on käytössä kolmenlaisia lainausmerkkejä:

  1. lainausmerkki "
  2. heittomerkki '
  3. Gravis, "käänteinen heittomerkki" ` (SHIFT-näppäimellä ?-merkin vierestä)

Lainausmerkkejä käytettäessä merkkijonossa olevat muuttujat korvataan näiden sisällöllä:

echo "Kotihakemistosi on $HOME"

Tulostaa jotain tällaista:

Kotihakemistosi on /home/kuivanen/

Heittomerkit taas aiheuttavat sen, että koko merkkijono tulkitaan "vain" merkkijonoksi, oli sisällä muuttujia tai ei:

echo 'Tietoa kotihakemistostasi säilytetään $HOME-muuttujassa.'

Tulostuu näin:

Tietoa kotihakemistostasi säilytetään $HOME-muuttujassa.

Gravis ` taas aiheuttaa niiden sisällä olevan komennon suorittamisen ja komennon tuottaman tulosteen tulostamisen tähän ("tulosta tähän"):

echo Today is `date "+%A"`

Tulosta tällaista:

Today is Monday (riippuen tietenkin päivästä, milloin tuo käsky annetaan...)


Komentotiedostot

Kun Linux-komentoja kootaan yhteen tiedostoon, tiedostoa kutsutaan komentotiedostoksi (komentojonoksi). Tällainen tiedosto on tekstitiedosto ja se voi sisältää myös komentotulkin ohjausrakenteita. Linuxissa (Unixissa) komentotulkkien komentokieli on yleensä hyvin laaja ja sen avulla voi tehdä usein hyvinkin monimutkaisia operaatioita. Useimmiten pienten operaatioiden tekoon käyttäjä ei oikeastaan tarvitse mitään erillistä ohjelmointikieltä, vaan homman voi hoitaa tyylikkäästi aivan komentotulkin ohjelmointikielellä. Näitä tällaisia kieliä kutsutaan usein yhteisnimityksellä "pienet ohjelmointikielet".

Koska komentotiedosto on tekstitiedosto, niitä voi tehdä millä tahansa editorilla.

Komentotiedostot kannattaa sijoittaa kotihakemistossa olevaan bin-hakemistoon, koska tämä hakemisto on usein jo oletuksena hakupolussa. Näin ollen tänne sijoitettuna suorituskelpoiset ohjelmat käynnistyvät pelkästään kirjoittamalla komentoriville tämän ohjelman nimen.

Tekstitiedostona komentotiedosto ei saa automaattisesti suoritusoikeuksia, vaan ne pitää sille erikseen antaa:

chmod +x tiedosto, tai:

chmod u+x tiedosto,

joka antaa suoritusoikeuden vain omistajalle. Ensimmäinen antaa sen kaikille.


Komentotulkin määrittäminen itse komentotiedostossa

Koska komentotulkkien komentokieli poikkeaa toisistaan eikä voida olla varmoja, mikä komentotulkki komentotiedoston käyttäjällä on käytössä, on siis jollain muulla tavalla varmistuttava siitä, että komentotulkki on oikea. Tämä onnistuu liittämällä komentotiedoston alkuun rivi, joka kertoo, missä komentotulkissa nämä käskyt suoritetaan:

#!/bin/sh

kertoo, että komennot suoritetaan sh-komentotulkissa (Bourne).

Yleisesti ottaen rivi alkaa merkeillä # ja !, jonka jälkeen kerrotaan käytettävä komentotulkki. Ne sijaitsevat yleensä /bin- tai /usr/bin-hakemistossa, mutta koko polku on kirjoitettava.

Samalla tekniikalla voit myös käyttää muita tulkkeja, esim. Perl-tulkin.


Komentoriviargumentit

Kun komentotiedosto käynnistetään, sille välitetään argumentteina koko komentorivi sanoiksi jaettuna. Nämä argumentit (parametrit) on talletettu muuttujiin $0, $1, ... $9. $0 on ohjelman nimi. Kaikki argumentit on välilyönnillä erotettuna muuttujassa $*. Argumenttien lukumäärä taas on löytyy muuttujasta $#.

Jottei tuosta jäisi kuvaa, että argumentteja voi olla vain 9, mainittakoon, että jos niitä on yli 9:n, loput saadaan shift-komennolla käyttöön. shift siirtää argumentteja oletuksena yhden pykälän vasemmalle ja pudottaa ensimmäisen pois. Tätä voi käyttää hyväkseen myös silloin, jos on tarpeellista, että käsiteltävä muuttuja on aina $1.

Esimerkki: (olkoon ohjelman nimi vaikkapa nayta)

#!/bin/sh
echo "Ohjelman nimi on $0"
echo "Toinen argumentti on $2"
echo "Ensimmäinen argumentti taas $1 ja argumentteja on yhteensa $#"
echo "Tässä kaikki argumentit:"
echo $*

Anna tiedostolle suoritusoikeudet ja kirjoita komentoriville:

nayta eka toka kolmas neljas

Mitä havaitsit?


Laskutoimituksia expr-apuohjelman avulla

expr-ohjelma on pieni apuohjelma, jonka yksi hyvä käyttöalue on juuri erilaisissa komentojonoissa tehdyt laskutoimitukset. Toki ohjelma toimii myös komentoriviltäkin:

expr 1 + 2

tulostaa yhteenlaskun 1 + 2 tuloksen, eli 3. expr-ohjelma tunnistaa yhteenlaskun lisäksi vähennyslaskun ( - ), kertolaskun ( * ) sekä jakolaskun ( / ). Huomaa, että kertolasku pitää tehdä näin:

expr 3 \* 4

Huomaa, ettei expr osaa laskea kuin kokonaislukuja. Lisäksi lukualue on pieni, vastaa C-kielen long-tyyppistä lukua, eli luvulle on varattu neljä tavua.

koska * on linuxissa erikoismerkki ja sen erikoismerkitys pitää tuossa kohdin peittää. Huomaa lisäksi, että jokaisen parametrin väliin tulee laittaa välilyönti. Parametreinä ajatelleen expr-ohjelmalla on siis kolme parametriä.

Esimerkki: Lasketaan kahden komentoriviparametrin summa ja sijoitetaan se summa- nimiseen muuttujaan:

#!/bin/sh
summa=`expr $1 + $2`
echo "Antamasi kahden luvun summa on $summa."

Koodissa on huomattava, että nyt tarvitaan gravis-heittomerkkiä. Operaatio toimii siis seuraavasti: expr-ohjelma saa tuloksen ja tämä tulos sijoitetaan expr-operaation tilalle koodiin. Näin tämä tulos saadaan sijoitettua summa-muuttujan arvoksi.

man expr

kertoo lisää, mihin expr pystyy.


test-ohjelma

test-ohjelma on toinen kätevä apuohjelma käytettäväksi komentotiedostoissa. Sillä voidaan testata lukujen kokoja toisiinsa verrattuna, merkkijonojen järjestystä sekä erinäisiä asioita tiedostoista (onko tiedostoa olemassa, onko se tiedosto, hakemisto tai jotain muuta, jne...)

test-ohjelman toimintaa on helpointa kuvata pienen esimerkin avulla:

#!/bin/sh
if test $1 -eq $2
then
echo "Antamasi luvut olivat yhtä suuret."
else
echo "Antamasi luvut olivat eri suuret."
fi

Esimerkissä testattiin kahden komentoriviparametrina annetun luvun yhtäsuuruutta. Jos annoit komentoriviparametrinä kaksi samaa lukua, ohjelma kertoo sen. Huomaa, ettei =-merkki käy tässä tapauksessa: sitä käytetään merkkijonojen aakkosjärjestystä tarkasteltaessa.

Lukujen tarkasteluun on käytettävissä seuraavat operaattorit:

  • -eq, yhtä suuri kuin
  • -ne, eri suuri kuin
  • -gt, suurempi kuin
  • -ge, suurempi tai yhtä suuri kuin
  • -lt, pienempi kuin
  • -le, pienempi tai yhtä suuri kuin

Kuten mainittu, test-ohjelmalla voidaan myös tarkastella tiedostoja levyltä. Esimerkiksi jos seuraavalle komentotiedostolle annetaan parametrinä hakemisto, se tulostaa hakemiston sisällön pitkässä muodossa:

#!/bin/sh
if test -d $1
then
ls -l $1 | less
else
echo "$1 ei ole hakemisto."
fi

 

man test

antaa (jälleen kerran) täydellisen tiedon siitä, mitä kaikkea test-ohjelmalla voi tehdä.

test-ohjelman sijasta voi käyttää myös hakasulkuja:

#!/bin/bash
if [ $1 -eq $2 ]
then
echo "Antamasi luvut olivat yhtä suuret."
else
echo "Antamasi luvut olivat eri suuret."
fi

Kontrollirakenteet

Unix- ja linux-maailmassa komentotulkit hallitsevat tavanomaiset ohjelmointikielten kontrollirakenteet, kuten ehtolauseen ja toistolauseen. Toistolauseista Bourne-komentotulkissa on käytössä sekä for- että while-rakenne. Näiden lisäksi myös tapausrakenne case on olemassa. Näin ollen pieniä ohjelmointitehtäviä hoitaa komentotiedostoilla aivan kätevästi, vaikkei osaisikaan mitään muuta ohjelmointikieltä.


Ehtolause

Ehtolause, kuten arvata saattaa, suorittaa lauseet vain silloin, kun annettu ehto on voimassa. Bournessa ehtolauseen muoto on seuraavanlainen:

Anna tiedostolle suoritusoikeudet ja kirjoita komentoriville:

if [ehto]
then 
[lauseet]
fi

Ehtolauseessa voi olla myös else-haara:

if [ehto]
then 
[lauseet]
else
[muita lauseita]
fi

elif taas jatkaa ehtoa:

if [ehto]
then 
[lauseet]
elif [toinen ehto]
then 
[muita lauseita]
else
[vielä jotain muita lauseita]
fi

Huomaa, että kirjoitustapa on tarkka: esimerkiksi then pitää ehdottomasti kirjoittaa eri riville kuin if-osa. Jos haluaa laittaa samalle riville, on käytettävä puolipistettä rivillä:

if [ehto]; then 
[lauseet]
fi

for-toistolause

for-lauseen yleinen muoto on seuraava:

for muuttuja [in arvojoukko]
do
lauseita
done 

Arvojoukon määrittäminen ei ole pakollista. Jos arvojoukkoa ei määritellä, otetaan for-lauseen arvojoukko komentoriviltä. Pari esimerkkiä selventää asiaa:

#!/bin/sh
summa=0
for luku in 1 2 3 4 5 6
do
  summa=`expr $summa + $luku`
done
echo "Lukujen 1 - 6 summa on $summa."

Jos otetaan arvojoukko pois, saadaan seuraavanlainen esimerkki:

#!/bin/sh
summa=0
for luku
do
  summa=`expr $summa + $luku`
done
echo "Lukujen $* summa on $summa."

Testaa itse, mitä koodinpätkä tekee. (Vihje: anna pari lukua komentoriviparametreiksi)

for-lauseella voi käsitellä myös tiedostoja:

#!/bin/sh
for tied in *
do
  echo $tied
done

Mitä mahtaakaan yllä oleva koodi tehdä?


while-toistolause

for-lauseen lisäksi toinen ohjelmointikielistä tuttu toistolause on while. Tämä rakenne löytyy myös Bourne-komentotulkin komentokielestä. Rakenteen toiminta on seuraava:

while ehto
do
lauseita
done

Esimerkki selventänee asiaa. Mitä seuraava ohjelma tekee?

#!/bin/sh
luku=10
while test $luku -ne 0
do
  echo $luku
  luku=`expr $luku - 1`
done

Tapausrakenne case

Ehtolauseella if voidaan yleensä testata vain kahta asiaa kerrallaan: onko jokin ehto voimassa vaiko ei. Näin ollen jos vaihtoehtoja on useita, tulee lauserakenteesta helposti erittäin pitkä sisäkkäisine ehtolauseineen. Tällaisissa tapauksissa saattaakin olla järkevämpää käyttää tapausrakennetta case, jonka muoto on seuraava:

case $muuttuja in
vaihtoehto1) lauseita ;;
vaihtoehto2) lauseita;;
...
*) lauseita;;
esac 

Viimeinen vaihtoehto ( * ) on eräänlainen oletusarvo: jos mikään aikaisemmista ei pätenyt, suoritetaan tämän takana olevat lauseet. *-haara ei ole pakollinen. Huomaa tapaushaarojen päättyminen kahteen puolipisteeseen!

Pieni esimerkki selventää asiaa. Kun kokeilet esimerkkiä, anna komentoriville erilainen määrä parametrejä:

#!/bin/sh
case $# in
0) echo "Et antanut yhtään parametriä.";;
1) echo "Annoit yhden parametrin";;
2) echo "Annoit kaksi parametriä.";;
*) echo "Annoit kolme tai useamman parametrin";;
esac

Lukeminen päätteeltä

Joskus tulee tilanteita, joissa pitäisi saada luku käyttäjältä. Tähän tarkoitukseen on Bournessa olemassa read-lause, jonka toimintaa seuraava esimerkki kuvastaa:

#!/bin/sh
echo "Ajattelen yhtä lukua. Yritä arvata se: "
read luku
echo "Lukuni oli `expr $luku + 1`. Hävisit niukasti!"

Alkuun