Shell-skriptin voi suorittaa kolmella perustavalla:
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).
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.
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ä).
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.
Ksh88 eroaa POSIXista funktioiden käsittelyssä muutamalla tärkeällä tavalla:
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.
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.
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
Shell laajentaa tekstikorvauksia aiheuttavat erikoismerkit komentoriviltä seuraavan toimintajärjestyksen mukaisesti:
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?