4  POSIX-shell-ohjelmoinnin perusteet

4.1  Shell-skriptien suoritustavat

Shell-skriptin voi suorittaa kolmella perustavalla:

  1. Antamalla sen shellille argumenttina:
    sh [options] file [argument...]
    Tällöin tiedoston pitää olla oletushakemistossa tai $PATHissa olevassa hakemistossa, tai sille pitää antaa (absoluuttinen tai suhteellinen) hakemistopolku. (Huom. kaikki shellit eivät kunnioita $PATHia tässä yhteydessä. Täydellinen polku toimii aina.)

    Tämä käynnistää uuden shellin, joka suorittaa skriptin. Uusi shell ei välttämättä ole sama kuin käynnissä oleva: tässä se voidaan (ja täytyy) nimetä suoraan komentorivillä (ja normaalit hakusäännöt määräävät mistä se löytyy, yleensä $PATHista).

    Uusi shell perii nykyisen ympäristömuuttujat muttei sisäisiä muuttujia eikä kaikkia muitakaan asetuksia (tästä enemmän myöhemmin).

  2. Kirjoittamalla tiedoston nimen sellaisenaan (mahdollisten argumenttien kanssa), on oltava $PATHissa, tai hakemistopolun kanssa. Huom. nyt sitä ei etsitä oletushakemistosta (ellei tämä ole $PATHissa). Lisäksi tiedoston suoritusbitin on oltava päällä (chmod +x). Siis esim.
    ./file.sh arg1 arg2

    Tässäkin käynnistyy uusi shell suorittamaan skriptiä, mutta mikä, riippuu tiedoston sisällöstä hieman monimutkaisella tavalla, joka vielä on systeemiriippuvainen ja standardoimaton (POSIX nimenomaan jätti asian auki), mutta yleensä se käy näin:

    Pääsääntöisesti skriptitiedoston alkuun kannattaa aina laittaa #! -rivi, vaikkei POSIX sitä vaadikaan. (Huom. jotkin systeemit vaativat välilyönnin !:n perään, eikä se missään tiettävästi haittaa, joten sitäkin kannattaa käyttää.) Huomaa kuitenkin että polkua voi joutua muuttamaan siirrettäessä skriptiä koneesta toiseen (sh:n jne sijainti vaihtelee).

    Tämä tapa on itse asiassa sama jolla yleensäkin suoritetaan ulkoisia komentoja.

  3. Kirjoittamalla . file
    ts. piste ja tiedostonimi; tiedoston hakuehdot kuten edellisessä ($PATH tai polku), mutta suoritusbittiä ei tarvita.

    Tämä eroaa edellisistä sillä ratkaisevalla tavalla, että shell suorittaa tiedoston sisältämät komennot itse: uutta prosessia ei käynnistetä, sisäiset muuttujat näkyvät (myös parametrit, komentorivillä tiedostonimen perässä mahdollisesti annetut argumentit eivät välity), kaikki asetukset säilyvät ja skriptin mahdollisesti tekemät muutokset muuttujiin yms jäävät voimaan. Tiedoston alussa mahdollisesti olevalla #!-rivillä ei ole merkitystä.

    Huom. kaksi edellämainittua toimii kaikissa shelleissä, tämä vain Bourne-tyyppisissä (mukaanlukien kaikki POSIX-yhteensopivat). Muissa shelleissä on kyllä yleensä omia vastaavia komentojaan (esim. csh:ssä source, mutta niillä voi aina kutsua vain saman shellin skriptejä).

4.2  Funktiot

Shellissä voi määritellä funktioita tyyliin

funcname() {
   ...
}

Funktiot toimivat kuin skriptit skriptin sisällä: Olennaisesti saman vaikutuksen voi saada kirjoittamalla uuden, erillisen skriptin, mutta funktiot ovat nopeampia jos niitä kutsutaan toistuvasti (jäävät muistiin) ja helpottavat koodin ylläpitoa, kun loogisesti yhteenkuuluvia kokonaisuuksia voi sijoittaa samaan tiedostoon.

Funktionmäärittelyn sisällä mahdollisesti olevia erikoismerkkejä ei käsitellä määrittelyvaiheessa, vaan vasta funktiota suoritettaessa.

Funktio perii kutsuvan skriptin ympäristön, trap-asetukset, optiot jne, mukaanlukien muuttujat paitsi parametrejä $1, $2..., jotka saavat arvoikseen funktion kutsussa annetut argumentit, sekä $#, joka on niiden lukumäärä. (Joissakin shelleissä myös $0 muuttuu, mutta POSIXin mukaan sen ei pitäisi.)

Kaikki funktion käyttäjät muuttujat (em. parametreja lukuunottamatta) ovat globaaleja ja vaikuttavat kutsuvaan skriptiin.

Funktion suoritus loppuu sen lopettavaan }-merkkiin tai return-käskyyn, ja paluuarvo on sama kuin sen viimeksi suorittaman komennon. (Funktion määrittelyn paluuarvo on 0 jos se onnistui, muuten jotain positiivista.)

Funktiomäärittelyn voi poistaa komennolla unset -f funcname.

Funktiot eivät periydy alishelleille.

4.2.1  Funktiot ksh:ssa

Ksh88 eroaa POSIXista funktioiden käsittelyssä muutamalla tärkeällä tavalla:

4.2.2  Aliakset ksh:ssa

POSIX ei tunne aliaksia, mutta jokseenkin kaikki POSIX-yhteensopivat shellit tuntevat. Ksh:ssa ne määritellään näin:

alias name=definition

Huom. =:n ympärillä ei saa olla tyhjää.

Aliaksille ei voi määritellä argumentteja, mutta aliaksen perässä oleva teksti jää sinne kun aliaskorvaus on tehty ja ajaa saman asian monessa yhteydessä (monimutkaisemmissa tarpeissa käytä funktiota).

Alias korvataan määrittelyllään vain rivin alussa, paitsi jos aliasmäärittely loppuu välilyöntiin, jolloin seuraavallekin sanalle tehdään aliaskorvaus tarvittaessa.

Aliaksia voi ketjuttaa, ts. aliaksen määrittely voi olla toinen alias.

Aliaksen voi poistaa komennolla unalias name. (unalias ei tunne mitään jokerimerkkejä, aliakset on poistettava yksitellen.)

Aliakset eivät periydy alishelleille.

Ksh määrittelee automaattisesti pysyvät aliakset joukolle yleisiä komentoja (sekä niiden löytämisen nopeuttamiseksi että Troijan hevosten teon vaikeuttamiseksi).

Yleensä skripteissä aliaksille on vähän tarvetta, funktiot toimivat paremmin; aliakset onkin ajateltu lähinnä interaktiiviseen käyttöön. Silti ne toimivat myös skripteissä ja saattavat aiheuttaa yllätyksiä ellei niitä ota huomioon.

4.3  Erikoismerkit

Shell tulkitsee joukon merkkejä omalla tavallaan, antaa niille erikoismerkityksen joka on poistettava (suojattava ne shellin tulkinnalta) jos sen haluaa estää.

Seuraavat erikoismerkit pitää aina suojata, jos niiden haluaa esittävän itseään:

| & ; < > ( ) $ ` \ " '
sekä välilyönti, tabulaattori ja rivinvaihto.

Seuraavat pitää suojata joissakin yhteyksissä muttei aina (kannattaa suojata varmuuden vuoksi ellei ole varma):

* ? [ # ~ = %

Shell tunnistaa muitakin erikoismerkkejä joissakin yhteyksissä, mutta niitä ei tarvitse suojata koska niillä on erikoismerkitys vain ko. yhteydessä.

Alkuperäisessä Bourne sh:ssa oli erikoismerkitys myös hattumerkillä ^ (se tarkoitti samaa kuin putkimerkki | nykyisin), joten joskus näkee sitäkin suojattavan; nykyisissä shelleissä se ei ole tarpeen.

4.3.1  Suojauskeinot

Erikoismerkkien suojaukseen on kolme tapaa:

Huom. nämä suojaavat erikoismerkit shellin tulkinnoilta, eri komennot saattavat tulkita niitä tai muita merkkejä kuitenkin, ja jos sama merkki on erikoinen sekä shellin että jonkin komennon mielestä, se voi olla tarpeen suojata kahdesti, esim.
tr '\\' /
tai
tr \\\\ /
Kummassakin tr saa argumentikseen kaksi kenoviivaa jotka se puolestaan tulkitsee yhdeksi.
Samoin esim. option alun merkkinä toimivaa viivaa ei voi näin suojata, vaan siihen tarvitaan komennosta riippuva optio, yleensä --:
rm -- -viivafile
tai muu vastaava keino:
rm ./-viivafile

4.3.2  Erikoismerkkien tulkintajärjestys

Shell laajentaa tekstikorvauksia aiheuttavat erikoismerkit komentoriviltä seuraavan toimintajärjestyksen mukaisesti:

  1. Tilde ~ , muuttujat ja parametrit ja komentokorvaus tehdään (erikoismerkit ~ , $ ja ` tulkitaan) vasemmalta oikealle (tai oikealta vasemmalle jos käytössä oleva kieli niin määrää)
  2. Rivi pilkotaan $IFS:in sisällön määräämällä tavalla kentiksi
  3. Tiedostonimet (polut) levitetään (*, ? jne)
  4. Lainausmerkit poistetaan (\, ` ja ")

Operaattorit ja uudelleensuuntausmerkit käsitellään myöhemmässä vaiheessa.

Seuraava: 4.4-4.5 Muuttujat, syöttö ja tulostus
Edellinen: 3. Mitä shell yleensä tekee?


File translated from TEX by TTH, version 1.98.
On 17 May 2001, 18:13.