BASH:issa ei tosiaan ole goto-komentoa - sillä BASH:issa koko sana goto jätetään pois vaikka toiminta säilyykin - itseasiassa koska myös palataan niin kyseessä on "gosub x of ..." tyyppinen sirpalekäsikranaatti.
Ei siis voi pompata rivinumeroon eikä label:iin vaan ainoastaan funktioon. Funktioon mennään kun sen nimi mainitaan joko selväkielisenä nimenä tai muuttujan arvona. Varsinkin kun mennään muuttujan arvon mukaiseen paikkaan on syytä kirjoittaa esimerkiksi näytölle tai tiedostoon mitä tehdään:
- sinne mihin pompataan: echo "tänne: ${FUNCNAME[0]} tultiin paikasta:" ${FUNCNAME[1]}
- sinne mistä lähdetään: echo "${FUNCNAME[0]} riviltä: $LINENO hypätään funktioon:"$funktion_nimi
- echo "skriptin nimi on: ${@: -0}"
- echo kutsupino: ${FUNCNAME
- kutsupinon merkitys: funktiolla tulee olla tieto mihin palata - tämä pino on kylläkin käyttäjän kannalta vain nähtäväksi. Kun johonkin funktioon mennään laitetaan paluuosoite pinoon ja palattua se poistetaan. Koska funktiot voivat kutsua toisiaan niin pinosta voi tulla huomattava - myös rekursiossa jokaisella kutsulla pino kasvaa.
- jos ei tuommoisia lisää niin vuosien kuluttua on tekijälle itsellekin täysi mysteeri kuinka johonkin on jouduttu.
- jos toteutus on sellainen että näyttö menisi sekaisin täytyy tulostaa tiedostoon. Silloin vain lisätään perään: > tiedostonimi.
------------------------------------------------------------------------------------------------
Parametritkin palautuvat automaattisesti - ellei hölmöile niinkuin usein neuvotaan. Käytännössä tuota parametrien siirtymistä kuvaava skripti voi olla seuraavantyyppinen:
#!/bin/bash
function lue () {
echo -n "kirjoita teksti "$1":"
read -e $1 # kirjoitettavaa voi editoida ja ääkkösetkin toimii
# sanoissa saa olla useampiakin epämääräisen pituisia välilyönti-jaksoja
# myös päätteen historiasta saa tekstiä nuolinäppäimillä.
}
lue a # huomaa että parametri on muuttujan nimi eikä arvo.
echo "a sai arvon:$a"
lue b
echo "a on vieläkin:$a ja b sai arvon:$b"
Koska funktiot ovat BASH:in "goto-käskyn" oleellinen osa on niitä syytä kuvata:
Funktio voidaan muodostaa kahdella tavalla:
1. funktion_nimi () { normaali BASH-skripti ; } # jolloin funktio jakaa muistialueen pääohjelman kanssa. Muodostuva funktio avautuu samaan prosessiin kutsujansa kanssa joten se on nopea - kutsu kestää noin 15 mikrosekuntia. Tätä tapaa käytetään lähes aina.
2. funktion_nimi () ( normaali BASH-skripti ; ) # siis sulut ovat muuttuneet kaarisuluiksi. Tällöin funktio muodostetaan omaan prosessiinsa joten sillä on muunmuassa ihan oma muistiavaruus. Sen kutsu kestää noin 350 mikrosekuntia, ja parametrien palauttaminen vaikeutuu. Mutta toiminnallisesti se on melkein samanlainen.
BASH:in funktioiden ominaisuuksista:
1. Funktio voi kutsua itseään ihan samallatavalla kuin muutkin. Rekursio on siis helppo toteuttaa. Ja rekursiosta voidaan palata joko lopetusehdon täytyttyä tai määräkertojen jälkeen tai...
2. jos mitään muuta ei määrätä palataan funktiosta kun se on kokonaan suoritettu ja palataan siihen lauseeseen mikä on heti kutsunjälkeen. Funktiossa voi kylläkin olla return-käsky kesken koodin mutta sekin palaa kusun jälkeiseen lauseeseen. Mutta on leegio menetelmiä joilla voi palata ihan jonnekin muualle - esimerkiksi toiseen funktioon ja kutsupinoa käsittelemällä paluu sieltä tapahtuu pääohjelmaan - tai esimerkiksi ctrl-c:llä funktioon joka selvitää miksi äsken hyydyttiin tai sekoiltiin.
- funktiolla voi olla melkeinpä millainen nimi hyvänsä, esimerkiksi ! tai ^ kelpaa hyvin tai mikä hyvänsä lause jossa ei ole välilyöntiä - välilyönnin voi korvata merkillä _ .
- pääohjelmassa voi kutsua vain funktioita jotka on määritelty jo. Mutta funktioissa voi kutsua sellaista joka määritellään vasta myöhemmin. Liitetyistä kirjastoista voidaan aina kutsua.
- normaalisti funktioiden ja pääohjeman muuttujat ovat yhteisiä joten parametrien palauttamiseen ei ole aina syytäkään. Mikäli funktiokutsussa on annettu sen muuttujan nimi jota halutaan muuttaa niin koska funktiossa voidaan määrätä esimerkiksi: read $1 ei parametria edes tarvitse palauttaa.
- pahat pojat väittävät ettei funktio kykene palauttamaan parametreja. Sillä on kuitenkin merkitystä vain silloin kun käytetään funktiokutsua joka toimii omassa prosessissaan - siis tuo aikaisemmin kuvattu tapa 2 jota ei juuri koskaan käytetä. Mutta keinoja palauttaa sittenkin parametreja on monia:
1. funktio voi kirjoittaa levylle ja pääohjelma lukee sen sieltä. Ja RAM-levyllä homma on nopeaakin.
2. Kuvaannollisesti käsky: a=$(joku_funktio jolla voi olla parametrejakin) lukee näytöltä mitä joku_funktio on tulostanut. Keino toimii olipa funktio globaalialueella tai omassa funktiossaan. Voidaan soveltaa useammallekin muuttujalle.
3. funktiolle annetaan parametriksi muuttujan nimi ja sitten koodissa jossakin määrätään esimerkiksi: read $1 - silloin syötetyn muuttujan arvo muuttuu. Ei siinä mitään eval-käskyä tarvita. Vaikka tämä menetelmä toimii vain globaalialueen funktioissa niin sillä on merkitystä koska silloin funktiota voidaan kutsua käsittelemään erinimisiä muuttujia niin että syötetyn muuttujan arvo muuttuu. Näin voidaan käsitellä vaikka kuinkamontaa muuttujaa.
- funktioille voi syöttää kahdentyyppisiä parametreja:
1. Arvo (by value). Tällöin vastaanottavassa päässä parametreihin viitataan: $1, $2 ....$N. Tai entisvanhaan: ${@:N} jolloin N:llä ei ole rajaa. Lopustapäin laskettuna toiseksiviimeinen: ${@:(-2):1}
2. Nimi. (by reference). Tällöin vastaanottavassa päässä parametriin viitataan: =${!N}
- seuraavilla parametreilla on erikoismerkitys:
$* parametrien joukko $0 mukaanlukien ( $0 on funktion nimi )
$@ parametrien joukko, sama kun kirjoittaisi "$1" "$2" "$3" .... Parametri $0 siis jää pois
$# parametrien lukumäärä, parametria $0 ei lasketa mukaan. Siis: [ $# -lt 1]" -> mikäli parametreja ei ole
$$ ytimen tunnus
$! viimeksi suoritetun prosessin tausta-prosessin tunnus
$? viimeksi suoritetun käskyn paluuarvo
$- oletusarvo?
$_ heti kutsun jälkeen suoritettavan skriptin täydellinen tiedostonimi ( siis polkuineen). Muulloin viimeiseksi suoritetun käskyn viimeinen argumentti.
Ohjelmille voidaan antaa myös optioita, miinus-merkin edeltämiä kirjainsarjoja tyyliin: ls -lpr
parametrien joukko ${@}
\$1 ---------------------> $1
\$2 ---------------------> $2
skriptin prosessinimi ${0} # joka on BASH_SOURCE pääohjelmassa
skriptiä polku ja nimi ${0%/*}
oma nimeni ${0##*/}