Komentotulkki on käyttöjärjestelmän komentotulkki. Bash on suosikkini komentotulkki, mutta jokainen Linuxin komentotulkki tulkkaa käyttäjän tai järjestelmänvalvojan kirjoittamat komennot muotoon, jota käyttöjärjestelmä voi käyttää. Kun tulokset palautetaan komentotulkkiohjelmaan, se lähettää ne STDOUT:iin, joka oletusarvoisesti näyttää ne terminaalissa. Kaikki tuntemani shellit ovat myös ohjelmointikieliä.
Ominaisuudet, kuten tabulaattoritäydennys, komentorivin palauttaminen ja muokkaaminen sekä pikanäppäimet, kuten aliakset, lisäävät sen arvoa tehokkaana shellinä. Sen oletusarvoinen komentorivin muokkaustila käyttää Emacsia, mutta yksi suosikkiominaisuuksistani Bashissa on se, että voin vaihtaa sen Vi-tilaan ja käyttää muokkauskomentoja, jotka ovat jo osa lihasmuistiani.
Jos kuitenkin ajattelet Bashia pelkästään komentorivin komentorivinä, menetät suuren osan sen todellisesta voimasta. Tutkiessani kolmiosaista Linuxin itseopiskelukurssia (johon tämä artikkelisarja perustuu) opin Bashista asioita, joita en ollut koskaan tiennyt yli 20 vuoden Linuxin parissa työskentelyn aikana. Osa näistä uusista tiedoista liittyy sen käyttöön ohjelmointikielenä. Bash on tehokas ohjelmointikieli, joka on suunniteltu täydellisesti käytettäväksi komentorivillä ja komentotulkkiskripteissä.
Tässä kolmiosaisessa sarjassa tutkitaan Bashin käyttöä CLI-ohjelmointikielenä (command-line interface). Tässä ensimmäisessä artikkelissa tarkastellaan yksinkertaista komentoriviohjelmointia Bashilla, muuttujia ja ohjausoperaattoreita. Muissa artikkeleissa tutustutaan Bash-tiedostojen tyyppeihin; merkkijono-, numeerisiin ja erilaisiin loogisiin operaattoreihin, jotka tarjoavat suorituksen kulunvalvontalogiikan; erilaisiin komentotulkin laajennustyyppeihin; ja toistuvia toimintoja mahdollistaviin for-, while- ja until-silmukoihin. Lisäksi tarkastellaan joitakin komentoja, jotka yksinkertaistavat ja tukevat näiden työkalujen käyttöä.
Kuoretulkki
Kuoretulkki on käyttöjärjestelmän komentotulkki. Bash on suosikkini komentotulkki, mutta jokainen Linuxin komentotulkki tulkkaa käyttäjän tai järjestelmänvalvojan kirjoittamat komennot muotoon, jota käyttöjärjestelmä voi käyttää. Kun tulokset palautetaan komentotulkkiohjelmalle, se näyttää ne terminaalissa. Kaikki tuntemani shellit ovat myös ohjelmointikieliä.
Bash on lyhenne sanoista Bourne Again Shell, koska Bash-kuori perustuu vanhempaan Bourne-kuoreen, jonka Steven Bourne kirjoitti vuonna 1977. Monia muitakin simpukankuoria on saatavilla, mutta nämä ovat ne neljä, joihin törmään useimmin:
- csh: C:n komentotulkki ohjelmoijille, jotka pitävät C-kielen syntaksista
- ksh: David Kornin kirjoittama ja Unix-käyttäjien suosima Korn-shell
- tcsh: Versio csh:sta, jossa on enemmän helppokäyttöisiä ominaisuuksia
- zsh: Z-kuori, joka yhdistää monia muiden suosittujen kuorien ominaisuuksia
Kaikissa kuorissa on sisäänrakennettuja komentoja, jotka täydentävät tai korvaavat ydinapuohjelmien tarjoamia komentoja. Avaa komentotulkin man-sivu ja etsi kohta ”BUILT-INS” nähdäksesi sen tarjoamat komennot.
Kullakin komentotulkilla on oma persoonallisuutensa ja syntaksinsa. Jotkut toimivat sinulle paremmin kuin toiset. Olen käyttänyt C-komentotulkkia, Korn-komentotulkkia ja Z-komentotulkkia. Pidän silti Bash-selaimesta enemmän kuin mistään niistä. Käytä sitä, joka sopii sinulle parhaiten, vaikka se saattaakin vaatia sinua kokeilemaan joitakin muita. Onneksi kuoren vaihtaminen on melko helppoa.
Kaikki nämä kuoret ovat ohjelmointikieliä sekä komentotulkkeja. Seuraavassa esitellään lyhyesti joitakin ohjelmointikonstruktioita ja -työkaluja, jotka ovat olennainen osa Bashia.
Bash ohjelmointikielenä
Useimmat sysadminit ovat käyttäneet Bashia antaakseen komentoja, jotka ovat yleensä melko yksinkertaisia ja suoraviivaisia. Bash voi kuitenkin mennä yksittäisten komentojen antamista pidemmälle, ja monet sysadminit luovat yksinkertaisia komentoriviohjelmia suorittamaan sarjan tehtäviä. Nämä ohjelmat ovat yleisiä työkaluja, jotka voivat säästää aikaa ja vaivaa.
Tavoitteeni CLI-ohjelmia kirjoittaessani on säästää aikaa ja vaivaa (eli olla laiska sysadmin). CLI-ohjelmat tukevat tätä listaamalla useita komentoja tietyssä järjestyksessä, jotka suoritetaan peräkkäin, joten sinun ei tarvitse seurata yhden komennon etenemistä ja kirjoittaa seuraavaa komentoa, kun ensimmäinen päättyy. Voit mennä tekemään muita asioita eikä sinun tarvitse jatkuvasti seurata jokaisen komennon etenemistä.
Mikä on ”ohjelma”?
Free On-line Dictionary of Computing (FOLDOC) määrittelee ohjelman seuraavasti: ”Tietokoneen suorittamat ohjeet, toisin kuin fyysinen laite, jolla ne suoritetaan.” Princetonin yliopiston WordNet määrittelee ohjelman seuraavasti: ”…ohjeiden sarja, jonka tietokone voi tulkita ja suorittaa…”. Wikipediassa on myös hyvä merkintä tietokoneohjelmista.
Siten ohjelma voi koostua yhdestä tai useammasta ohjeesta, jotka suorittavat tietyn, toisiinsa liittyvän tehtävän. Tietokoneohjelman ohjetta kutsutaan myös ohjelmalauseeksi. Järjestelmänvalvojille ohjelma on yleensä komentotulkkikomentojen sarja. Kaikissa Linuxiin saatavilla olevissa komentokuorissa, ainakin niissä, jotka minä tunnen, on ainakin perusmuotoinen ohjelmointikyky, eikä Bash, joka on useimpien Linux-jakeluiden oletuskomentotulkki, ole poikkeus.
Tässä sarjassa käytetään Bashia (koska se on niin yleinen), mutta jos käytät toista komentotulkkia, yleiset ohjelmointikonseptit pysyvät samoina, vaikkakin konstruktiot ja syntaksit saattavat poiketa jonkin verran. Jotkin shellit saattavat tukea joitakin ominaisuuksia, joita toiset eivät tue, mutta kaikki tarjoavat jonkin verran ohjelmointimahdollisuuksia. Shell-ohjelmat voidaan tallentaa tiedostoon toistuvaa käyttöä varten, tai ne voidaan luoda komentorivillä tarpeen mukaan.
Yksinkertaiset CLI-ohjelmat
Yksinkertaisimmat komentoriviohjelmat ovat yksi tai kaksi peräkkäistä ohjelmalausetta, jotka voivat liittyä toisiinsa tai olla liittymättä toisiinsa ja jotka kirjoitetaan komentoriville ennen Enter-näppäimen painamista. Ohjelman toinen lauseke, jos sellainen on, saattaa olla riippuvainen ensimmäisen lausekkeen toimista, mutta sen ei tarvitse olla.
On myös yksi syntaktinen välimerkki, joka on sanottava selvästi. Kun komentoriville syötetään yksittäinen komento, Enter-näppäimen painaminen päättää komennon implisiittiseen puolipisteeseen (;). Kun käytetään CLI-komentotulkkiohjelmaa, joka syötetään yhdeksi riviksi komentoriville, puolipistettä on käytettävä päättämään jokainen lauseke ja erottamaan se seuraavasta lausekkeesta. CLI-komentotulkkiohjelman viimeisessä lausekkeessa voidaan käyttää eksplisiittistä tai implisiittistä puolipistettä.
Joitakin perussyntaksia
Seuraavat esimerkit selventävät tätä syntaksia. Tämä ohjelma koostuu yhdestä komennosta, jossa on eksplisiittinen lopetusmerkki:
$ echo "Hello world." ;
Hello world.
Tämä ei ehkä tunnu kovin kummoiselta ohjelmalta, mutta se on ensimmäinen ohjelma, johon törmään jokaisella uudella ohjelmointikielellä, jonka opettelen. Syntaksi voi olla hieman erilainen kullakin kielellä, mutta tulos on sama.
Kehitetäänpä hieman tätä triviaalia, mutta kaikkialla esiintyvää ohjelmaa. Sinun tuloksesi eroavat minun tuloksistani, koska minä olen tehnyt muita kokeiluja, kun taas sinulla saattaa olla vain oletushakemistot ja -tiedostot, jotka luodaan tilin kotihakemistoon, kun kirjaudut tilille ensimmäistä kertaa GUI-työpöydän kautta.
$ echo "My home directory." ; ls ;
My home directory.
chapter25 TestFile1.Linux dmesg2.txt Downloads newfile.txt softlink1 testdir6
chapter26 TestFile1.mac dmesg3.txt file005 Pictures Templates testdir
TestFile1 Desktop dmesg.txt link3 Public testdir Videos
TestFile1.dos dmesg1.txt Documents Music random.txt testdir1
Tässä on hieman enemmän järkeä. Tulokset liittyvät toisiinsa, mutta yksittäiset ohjelmalausekkeet ovat toisistaan riippumattomia. Huomaa, että laitan mielelläni välilyöntejä ennen ja jälkeen puolipisteen, koska se tekee koodista hieman helpommin luettavaa. Kokeile tuota pientä CLI-ohjelmaa uudelleen ilman nimenomaista puolipistettä lopussa:
$ echo "My home directory." ; ls
Tulosteissa ei ole eroa.
Jotain muuttujista
Kuten kaikki ohjelmointikielet, myös Bash-komentotulkki osaa käsitellä muuttujia. Muuttuja on symbolinen nimi, joka viittaa tiettyyn paikkaan muistissa, joka sisältää jonkinlaisen arvon. Muuttujan arvo on muutettavissa eli se on muuttuva.
Bash ei tyypittele muuttujia kuten C ja siihen liittyvät kielet määrittelemällä ne kokonaisluvuiksi, liukuluvuiksi tai merkkijonotyypeiksi. Bashissa kaikki muuttujat ovat merkkijonoja. Merkkijonoa, joka on kokonaisluku, voidaan käyttää kokonaislukuaritmetiikassa, joka on ainoa matematiikkatyyppi, johon Bash pystyy. Jos tarvitaan monimutkaisempaa matematiikkaa, CLI-ohjelmissa ja skripteissä voidaan käyttää bc-komentoa.
Muuttujille annetaan arvoja, ja niitä voidaan käyttää viittaamaan näihin arvoihin CLI-ohjelmissa ja skripteissä. Muuttujan arvo asetetaan käyttämällä sen nimeä, mutta sitä ei edeltää $-merkki. Määritys VAR=10 asettaa muuttujan VAR arvoksi 10. Voit tulostaa muuttujan arvon käyttämällä lauseketta echo $VAR. Aloita tekstimuuttujilla (eli muilla kuin numeerisilla muuttujilla).
Bash-muuttujista tulee osa komentotulkin ympäristöä, kunnes niiden asettaminen peruutetaan.
Tarkista sellaisen muuttujan alkuarvo, jota ei ole annettu; sen pitäisi olla nolla. Määritä sitten muuttujalle arvo ja tulosta se sen arvon tarkistamiseksi. Voit tehdä kaiken tämän yhdellä CLI-ohjelmalla:
$ echo $MyVar ; MyVar="Hello World" ; echo $MyVar ;
Hello World
$
Huomautus: Muuttujan osoittamisen syntaksi on hyvin tiukka. Osoituslauseessa ei saa olla välilyöntejä yhtäläisyysmerkin (=) kummallakaan puolella.
Tyhjä rivi osoittaa, että MyVarin alkuarvo on nolla. Muuttujan arvon muuttaminen ja asettaminen tapahtuu samalla tavalla. Tässä esimerkissä näkyy sekä alkuperäinen että uusi arvo.
Kuten mainittiin, Bash voi suorittaa kokonaislukuaritmeettisia laskutoimituksia, mikä on hyödyllistä, kun lasketaan viittaus elementin sijaintiin joukossa tai tehdään yksinkertaisia matemaattisia ongelmia. Se ei sovellu tieteellisiin laskutoimituksiin tai mihinkään, joka vaatii desimaalilukuja, kuten rahoituslaskentaan. Tällaisiin laskutoimituksiin on olemassa paljon parempia työkaluja.
Tässä on yksinkertainen laskutoimitus:
$ Var1="7" ; Var2="9" ; echo "Result = $((Var1*Var2))"
Result = 63
Mitä tapahtuu, kun suoritat matemaattisen operaation, jonka tuloksena on liukuluku?
Tulos on lähin kokonaisluku. Huomaa, että laskutoimitus suoritettiin osana echo-komennon lauseketta. Matematiikka suoritetaan ennen ympäröivää echo-komentoa Bashin etusijajärjestyksen vuoksi. Katso lisätietoja Bashin man-sivulta ja etsi hakusanalla ”precedence.”
Kontrollioperaattorit
Shellin kontrollioperaattorit ovat yksi syntaktisista operaattoreista, joiden avulla voit helposti luoda mielenkiintoisia komentoriviohjelmia. Yksinkertaisin CLI-ohjelman muoto on vain useiden komentojen ketjuttaminen peräkkäin komentoriville:
command1 ; command2 ; command3 ; command4 ; . . . ; etc. ;
Nämä komennot toimivat kaikki ongelmitta niin kauan kuin virheitä ei tapahdu. Mutta mitä tapahtuu, kun virhe tapahtuu? Voit ennakoida ja sallia virheet käyttämällä sisäänrakennettuja &&- ja || Bash-ohjausoperaattoreita. Nämä kaksi ohjausoperaattoria tarjoavat jonkin verran virtauksen hallintaa ja mahdollistavat koodin suoritusjärjestyksen muuttamisen. Puolipistettä pidetään myös Bash-ohjausoperaattorina, samoin kuin rivinvaihtomerkkiä.
&&-operaattori sanoo yksinkertaisesti: ”Jos komento1 onnistuu, suorita komento2. Jos komento1 epäonnistuu jostain syystä, komento2 jätetään väliin”. Tämä syntaksi näyttää tältä:
command1 && command2
Katsotaan nyt komentoja, jotka luovat uuden hakemiston ja – jos se onnistuu – tekevät siitä nykyisen työhakemiston (PWD). Varmista, että kotihakemistosi (~) on PWD. Kokeile tätä ensin hakemistossa /root, johon sinulla ei ole pääsyä:
Virheen antoi komento mkdir. Et saanut virheilmoitusta siitä, että tiedostoa ei voitu luoda, koska hakemiston luominen epäonnistui. &&-ohjausoperaattori havaitsi nollasta poikkeavan paluukoodin, joten kosketus-komento ohitettiin. Ohjausoperaattorin && käyttäminen estää kosketuskomennon suorittamisen, koska hakemiston luomisessa tapahtui virhe. Tämäntyyppinen komentoriviohjelman kulunvalvonta voi estää virheiden kasautumisen ja todellisen sotkun syntymisen. Mutta nyt on aika mennä hieman monimutkaisemmaksi.
Hallintaoperaattorin || avulla voit lisätä toisen ohjelmalauseen, joka suoritetaan, kun alkuperäinen ohjelmalause palauttaa koodin, joka on suurempi kuin nolla. Perussyntaksi näyttää tältä:
command1 || command2
Tämä syntaksi kuuluu: ”Jos komento1 epäonnistuu, suorita komento2”. Tämä tarkoittaa, että jos komento1 onnistuu, komento2 ohitetaan. Kokeile tätä yrittämällä luoda uusi hakemisto:
Tämä on juuri sitä, mitä voisit odottaa. Koska uutta hakemistoa ei voitu luoda, ensimmäinen komento epäonnistui, mikä johti toisen komennon suorittamiseen.
Yhdistämällä nämä kaksi operaattoria saadaan molempien parhaat puolet. Ohjausoperaattorin syntaksi, jossa käytetään jonkin verran virranohjausta, saa tämän yleisen muodon, kun käytetään &&- ja ||-ohjausoperaattoreita:
preceding commands ; command1 && command2 || command3 ; following commands
Tämä syntaksi voidaan esittää näin: ”Jos komento1 poistuu paluukoodilla 0, suorita komento2, muuten suorita komento3”. Kokeile:
Kokeile nyt viimeistä komentoa uudelleen käyttäen kotihakemistoasi /root-hakemiston sijasta. Sinulla on oikeus luoda tämä hakemisto:
$ Dir=~/testdir ; mkdir $Dir && cd $Dir || echo "$Dir was not created."
$
Hallintaoperaattorin syntaksi, kuten komento1 && komento2, toimii, koska jokainen komento lähettää komentotulkille paluukoodin (return code, RC), joka ilmaisee, onko komento suoritettu onnistuneesti vai tapahtuiko suorituksessa jonkinlainen virhe. Konvention mukaan RC-koodi nolla (0) tarkoittaa onnistumista, ja mikä tahansa positiivinen luku tarkoittaa jonkinlaista epäonnistumista. Jotkin järjestelmänvalvojien käyttämät työkalut palauttavat vain ykkösen (1) osoittaakseen epäonnistumisen, mutta monet käyttävät muita koodeja ilmaisemaan tapahtuneen epäonnistumisen tyypin.
Bashin komentotulkin muuttuja $? sisältää edellisen komennon RC-koodin. Tämän RC:n voi tarkistaa hyvin helposti komentosarjasta, komentoluettelon seuraavasta komennosta tai jopa suoraan sysadminilta. Aloita suorittamalla yksinkertainen komento ja tarkista heti RC. RC on aina viimeisimmälle komennolle, joka suoritettiin ennen kuin katsoit sitä.
Tässä tapauksessa RC on nolla, mikä tarkoittaa, että komento suoritettiin onnistuneesti. Kokeile nyt samaa komentoa rootin kotihakemistossa, hakemistossa, johon sinulla ei ole oikeuksia:
Tässä tapauksessa RC on kaksi; tämä tarkoittaa, että muulta kuin root-käyttäjältä evättiin lupa päästä hakemistoon, johon käyttäjällä ei ole oikeuksia. Ohjausoperaattorit käyttävät näitä RC:itä, jotta voit muuttaa ohjelman suoritusjärjestystä.
Yhteenveto
Tässä artikkelissa tarkasteltiin Bashia ohjelmointikielenä ja tutustuttiin sen perussyntaksiin sekä muutamiin perustyökaluihin. Siinä näytettiin, miten tietoja tulostetaan STDOUTiin ja miten muuttujia ja ohjausoperaattoreita käytetään. Sarjan seuraavassa artikkelissa tarkastellaan joitakin Bashin monista loogisista operaattoreista, jotka ohjaavat käskyjen suorituksen kulkua.