ITKA203 Käyttöjärjestelmät -kurssin Demo 2 keväällä 2015 ja 2016. "Superpikajatko interaktiivisen Unix-shellin käyttöön"
Paavo Nieminen, paavo.j.nieminen@jyu.fi
Jyväskylän yliopiston tietotekniikan laitos.
STATUS: Saa alkaa palauttaa. Raportoikaa ongelmista heti, jos ilmenee.
Contents
Tämä materiaali syntyi keväällä 2014, ja sitä on pienin muutoksin käytetty 2015. Pieniä muokkauksia saatetaan tehdä keväällä 2016, jos ensimmäisten tekijöiden osalta ilmenee jotain yllättäviä ongelmia. Demo on hieman lyhempi kuin ensimmäinen, mutta se rakentuu vahvasti edellisen päälle. Kertaile tarvittaessa ja tee itselle lisämuistiinpanoja, jos tuntuu että tarvitset!
Tarkoitus on jatkaa ensimmäisen demon pohjalta interaktiivisen shellin, erityisesti bashin, tehokäyttöä muutamien elämää helpottavien niksien kautta. Tutustutaan kurssin luennoissa meneillään oleviin tai pian esille tuleviin asioihin käytännössä. Lisäksi hankitaan lisää kädentaitoja tutustumalla joihinkin näppäriin apuohjelmiin. Tutkitaan binääritiedostoja omin käsin heksavedoksina. Tehdään myös ensimmäinen, tässä vaiheessa vielä hyvin triviaali, skripti eli komentoriviohjelma.
Tämän demon voi vielä tehdä Jyväskylän yliopiston yleisillä suorakäyttökoneilla (jalava, halava). Pysyttele silloin varovaisesti ohjeen mukaisissa toiminnoissa. Kurssin puolivälin jälkeen tullaan käyttämään kurssin omaa testipalvelinta itka203-testi.it.jyu.fi, jossa voidaan leikkiä vapaammin ja muita käyttäjiä häiritsemättä, mutta hintana on mm. se että verkkolevyn kotihakemistoa ("U-asema") ei ole kytketty, koneella sijaitsevia tietoja ei varmuuskopioida ja palvelin saattaa lakata toimimasta kesken kaiken.
Harjoituksen tavoitteet:
- Shellin ja pääteyhteyden käyttö sujuvoituu.
- Kurssin käsitteet konkretisoituvat itse naputtelemiesi esimerkkien kautta nähtynä.
- Teet ensimmäisen skriptin.
Muista ensimmäisen demon varoitukset! Ajattele ennen kuin kirjoitat, ja ajattele uudelleen ennen kuin painat enteriä. Muutenkin voi kerrata asioita ensimmäisestä superpikaintrosta.
Keväällä 2015 määriteltyjen osaamistavoitteiden osalta demon tehtyään opiskelija:
Jatketaan siitä, mihin aiemmin jäätiin (kertaile, jos on epäselvää): Osaat ottaa ssh-yhteyden yliopiston Linux-palvelimeen ja ymmärrät antavasi Bourne Again Shell (bash) -nimiselle shellille tekstimuotoisia komentorivejä, jotka shell suorittaa melko läheisessä yhteistoiminnassa palvelimeen asennetun käyttöjärjestelmän kanssa. Valtaosa tästä tekstimuotoisesta rajapinnasta on määritelty POSIX-standardissa, mutta GNU/Linux -ympäristössä on käyttömukavuutta ja -tehokkuutta helpottavia laajennoksia, joita hyödynnämme myös.
Nyt olet saanut haltuun varsin näppärän työkalun etäyhteyksien käyttöön. Kehitä taitojasi screenin kanssa myös jatkossa koko ajan. Otetaan vielä pari elämää helpottavaa kikkaa ensimmäisessä demossa nähtyjen lisäksi ihan vaan motivoivina esimerkkeinä; asiasta kiinnostuneet löytänevät lisää omatoimisesti Internetin tutoriaaleista.
Aiemmassa demossa tutustuit interaktiivisen bash-shellin komentorivin editointiin ja edellisten komentojen hakemiseen komentohistoriasta nuolinäppäimiä käyttäen sekä tiedostojen nimien täydentämiseen tabulaattorilla (muistele ja kertaa tarvittaessa). Pidemmän päälle voi olla hyödyllistä viedä "selkäytimeen" näppäinyhdistelmät, joilla saman voi tehdä siirtämättä käsiä nuolinäppäimille. Nämä samat näppäinyhdistelmät toimivat myös monissa tekstipohjaisissa sovellusohjelmissa, kuten joissakin tekstieditoreissa:
Ctrl-p vastaa nuolta ylös ("p" == previous line) Ctrl-n vastaa nuolta alas ("n" == next line) Ctrl-f vastaa nuolta oikealle ("f" == forward) Ctrl-b vastaa nuolta vasemmalle ("b" == backward) Ctrl-e vastaa end-näppäintä ("e" == end) Ctrl-a vastaa home-näppäintä ("a" == ??) HUOM: Screeniä käytetäessä Ctrl-a on oletuksena komentonäppäin, joten varsinaisen Ctrl-a:n tuottaminen vaatii screenissä tuplanäppäilyn: "Ctrl-a a" eli ensin Ctrl-a ja sitten erikseen a.
Näppäinyhdistelmät vaikuttaisivat periytyvän aiemmista käytänteistä aina 1960- ja 1970-luvuilta saakka. Tarkkaavaisten opiskelijoiden löytämiä linkkejä historiakatsauksiin näppäilyjen osalta:
Kun näitä lähdet kokeilemaan, huomaa, että viereisistä näppäimistä tapahtuu sitten jotain aivan muuta. Suurin osa niistä on erittäin hyödyllisiä toimenpiteitä tehokäyttäjälle, mutta saattavat joskus yllättää varomattoman näppäilijän, joka ei osu alunperin tarkoittamaansa näppäimeen. Tässä potentiaalisimpia yllätysten aiheuttajia:
Ctrl-c tyypillisesti lopettaa käynnissä olevan ohjelman Ctrl-z tyypillisesti pysäyttää käynnissä olevan ohjelman (tätä kokeiltiin demon alussa nano-editorissa) Ctrl-d tyhjän rivin alussa painettuna lähettää hangup-viestin, jolloin mm. shell loppuu saman tien ikään kuin olisi kirjoitettu komento "exit". Eipähän jatkossa tule yllätyksenä, jos yhteys katkeaa tästä syystä saman tien, vahingossa tai tahallaan. "Lepääminen d-kirjaimen päällä", niin että tulee automaattisesti monta Ctrl-d -painallusta, aiheuttaapi kaikkien screenissä olevien shell-ikkunoiden sulkeutumisen yksi kerrallaan, viimeisen sulkeutuessa itse screen-ohjelman sulkeutumisen ja seuraavaksi vielä koko pääteyhteyden sulkeutumisen. Rivin keskellä painettuna poistaa osoittimen alla olevan kirjaimen ("d" == delete) Ctrl-j Sama kuin enter, ts. komento lähtee saman tien.. VARO, jne.. Ctrl-m Myös sama kuin enter, ts. komento lähtee saman tien.. VARO, jne.. Ctrl-o Myös sama kuin enter, ts. komento lähtee saman tien.. VARO, jne.. Ctrl-i Sama kuin tabulaattori, eli voi käyttää tiedostonimien täydentämiseen Ctrl-l Eli ällä. Tyhjentää terminaalinäkymän kuten komento clear. ("l" == cLear(?)) Ctrl-s Pysäyttää tekstien saapumisen käyttäjälle päin (terminaalin standardisisääntulo), ei vaikuta palvelimelle päin meneviin näppäilyihin. Voi siis vaikuttaa ikään kuin yhteys olisi "jumissa", vaikkei se oikeasti ole. ("s" == ?? ks. edellä mainittu opiskelijan löytämä linkki historiakatsaukseen) Ctrl-q Jatkaa tekstien näyttämistä käyttäjälle päin, eli "korjaa Ctrl-s:n aiheuttaman näennäisen 'jumittumisen'" ("q" == ?? ks. edellä mainittu opiskelijan löytämä linkki historiakatsaukseen)
Komentorivin editointia tehostavat entisestään mm. seuraavat näppäilyt:
Ctrl-k Leikkaa rivin lopun osoittimesta oikealle päin komentorivin omalle leikepöydälle ("k" == kill) Ctrl-u Leikkaa rivin alun osoittimesta vasemmalle päin komentorivin omalle leikepöydälle ("u" == ??) HUOM: Macissä vaikuttaisi toimivan eri tavoin: Ctrl-u leikkaa koko rivin leikepöydälle riippumatta kursorin sijainnista. Ilmoitelkaahan, jos huomaatte muitakin erilaisuuksia Mac-maailmassa. Ctrl-y Liittää pätkän takaisin komentorivin omalta leikepöydältä. ("y" == yank)
Erityisen tehokas tehokäyttönäppäin on lisäksi seuraava:
Ctr-r Aktivoi ominaisuuden, jolla komentohistoriasta voi etsiä kauan sitten tehtyä komentoriviä, joka sisältää merkkejä. ("r" == reverse-search) Jos olet esim. 3 päivää sitten tehnyt jotain eksoottista, mikä nyt pitäisi toistaa, niin riittää muistaa muutama leimallinen pätkä kyseisestä komennosta.
Kokeile edellisiä ja koeta saada niistä hyödyllisimmät selkäytimeen. Vaaraa ei ole silloin, kun tiedät, että näppäilysi ei tule suorittamaan sellaista komentoa, joka tuhoaisi dataa poistamalla tiedostoja tai kirjoittamalla niiden päälle.
Turvallisin ympäristö epävarmoille näppäilijöille on halavan/jalavan sijasta ottaa pääteyhteys tätä kurssia varten perustettuun testipalvelimeen itka203-testi.it.jyu.fi - sinne syntyy ensimmäisen kirjautumisen yhteydessä täysin oma, erillinen kotihakemisto, jolla ei ole yhteyttä yleiseen verkkolevyyn, jossa tärkeät tiedostosi sijaitsevat. Kyseiselle testipalvelimelle ei kuitenkaan myöskään pidä jättää mitään tärkeätä, kuten lopullisia demovastauksia, koska sen sisältö suorastaan luvataan tuhota aika ajoin. Kurssin loppupuolella siellä toivon mukaan tehdään vapaaehtoista demoa, jonka suoranaisena tarkoituksena on saada palvelimen muisti täyteen ja toiminta muutenkin tukkoon. Tässä vaiheessa kurssia se tarjoaa turvallisen, maailmalta eristetyn, ympäristön shellin kokeiluun esimerkiksi tässä demossa.
Luennoilla on tarkoitus aivan alkuvaiheesta asti käyttää komentoja, joilla käyttöjärjestelmän ja tietokoneen tilannetta voidaan tarkastella shellistä käsin. Tarkoitus tässä demossa on, että kokeilet näitä työkaluja aivan omin käsin, jotta mieleen jää yleiskuva siitä, millaisia työkaluja esimerkiksi on olemassa. Oman kokemuksen kautta ymmärrät paremmin myös, mistä luennolla milloinkin puhutaan.
Näytä oman shell-session prosessit:
ps
Tuloste näyttänee jotakuinkin seuraavalle:
[nieminen@itka203 ~]$ ps PID TTY TIME CMD 26837 pts/0 00:00:00 bash 32559 pts/0 00:00:00 ps
Vasemmanpuoleinen sarake (PID) kertoo kunkin prosessin yksilöivän numeron; tästä lisää kurssin mittaan. Toinen sarake (TTY) kertoo sen terminaalin nimen, josta prosessia ohjataan ("tty" == TeleTYpewriter; varsin historiallinen nimike). Kolmas sarake (TIME) kertoo, kuinka paljon prosessi on käyttänyt suoritusaikaa yhteensä. Ylläolevassa tuloste-esimerkissä käyttäjä "nieminen" ei ole käyttänyt kovinkaan paljon yhteisiä resursseja. Tekstipohjaiset sovellukset käyttävät häviävän pieniä määriä aikaa, toisin kuin laskentaintensiiviset sovellukset; tästäkin paljon lisää kurssin mittaan. Viimeinen sarake (CMD) kertoo komennon, jolla kukin prosessi on käynnistetty.
Näytä kaikki tietyn käyttäjän prosessit (korvaa "nieminen" vaikka omalla tunnuksellasi tai millä vaan):
ps -u nieminen
Näytä kaikkien käyttäjien prosessit ("e" == every??):
ps -e
Näytä enemmän tietoja ("f"==full) yhden käyttäjän prosesseista:
ps -f -u nieminen
Tämä tuloste kertoo prosessin ID-tunnuksen ja komennon lisäksi myös muita tietoja. Saattaa näyttää vähän tältä:
UID PID PPID C STIME TTY TIME CMD nieminen 1023 26837 0 20:12 pts/0 00:00:00 ps -f -u nieminen nieminen 14995 1 0 Feb19 ? 00:00:00 SCREEN nieminen 14996 14995 0 Feb19 pts/1 00:00:00 /bin/bash nieminen 15010 14995 0 Feb19 pts/2 00:00:00 /bin/bash nieminen 26836 26806 0 19:16 ? 00:00:00 sshd: nieminen@pts/0 nieminen 26837 26836 0 19:16 pts/0 00:00:00 -bash
Ensimmäinen sarake (UID) ilmoittaa nyt käyttäjän, jonka oikeuksin prosessia suoritetaan. Toinen sarake (PID) yksilöi prosessin. Kolmas sarake (PPID) ilmoittaa sen prosessin, joka on pyytänyt rivillä näytetyn prosessin käynnistymistä, tämän nimi on luontevasti vanhempiprosessi (ppid = "parent process id"). Neljäs sarake (C) kertoisi, kuinka paljon prosessoriaikaa kukin prosessi vie; tässä esimerkissä suoritusaika ei vaikuttaisi kovin relevantilta kysymykseltä. Viides sarake (STIME) kertoo, mihin aikaan prosessi on käynnistetty. Kuudes sarake (TTY) on jälleen terminaalin nimi. Seitsemäs (TIME) kertoo jälleen, paljonko prosessoriaikaa prosessi on vaatinut. Täydemmässä tulosteessa viimeinen sarake (CMD) on myös täydellisempi. Se kertoo pelkän komennon lisäksi myös argumentit, jotka komentorivillä on annettu.
Valitsimia voi yhdistellä. Esimerkiksi näytä enemmän tietoja kaikkien käyttäjien prosesseista:
ps -f -e
Tämän komennon tulosteessa osa riveistä on muiden normaalien käyttäjien prosesseja, mutta osa puolestaan on järjestelmän palveluiden prosesseja, jotka toimivat käyttäjäoikeuksin. Tällä tavoin voidaan rajata palveluiden oikeuksia samalla tavoin kuin normaalien käyttäjienkin. Kaikkien palveluiden ei missään nimessä tarvitse päästä käsiksi kaikkialle, koska ensinnäkin jokainen avoimeksi jätetty ovi on potentiaalinen tietoturva-aukko. Sen sijaan kukin palvelu kannattaa suunnitella käynnistettäväksi sellaisen käyttäjätunnuksen alle, jolla on minimaaliset oikeudet täsmälleen kyseisen palvelun toteuttamiseksi. Esimerkiksi WWW-palvelimella ei missään nimessä saisi olla kirjoitusoikeutta koko järjestelmään. Sen toiminta on syytä rajata esimerkiksi httpd -nimiselle käyttäjälle tai ryhmälle määrättyihin oikeuksiin.
Tuloste alkaa todennäköisesti seuraavalla rivillä:
UID PID PPID C STIME TTY TIME CMD root 1 0 0 Jan28 ? 00:00:16 /sbin/init root 2 0 0 Jan28 ? 00:00:01 [kthreadd]
Tuo käyttäjä root on kaikkivoipaisin käyttäjä, jonka oikeuksin voi tehdä järjestelmässä mitä vain. Prosessi, jonka id-numero on 1 ja komento /sbin/init on erikoisroolissa: käynnistyksen yhteydessä käyttöjärjestelmä käynnistää kyseisen init-prosessin, ja kaikki muut sittemmin käynnistetyt prosessit ovat sen lapsia. Myös prosessi 2, käyttöjärjestelmän säikeitä hallitseva palvelu, on erikoisroolissa (järjestelmä on käynnistänyt sen "ilman vanhempaa" eli ppid==0). Kaikki loput prosessit ovat jomman kumman prosessin (1 tai 2) jälkikasvua. Voinet verifioida tämän saamastasi tulosteesta.
Kokeile vielä seuraavaa epästandardia laajennosta, joka näyttää oikeanpuoleisessa sarakkeessa kauniina "ASCII-grafiikkana", mikä prosessi on minkäkin toisen prosessin lapsi tai vanhempi:
ps -e -f --forest
Prosessin 2 (kthreadd) lapsia ovat laitteistoa käsittelevät palvelut. Prosessin 1 lapsia ovat vähemmän laiteläheiset palvelut, mm. sshd -palvelu, joka odottaa salattuja pääteyhteyksiä, kuten se, jota tällä hetkellä käyttelet.
Vielä yksi tapa tutkia prosesseja... komenna:
top
Top näyttää reaaliaikaisen tilanteen prosesseista ja niiden aiheuttamasta resurssikuormasta. Topista pääsee pois näppäilemällä q.
Lisää tietoa ja kustomointimahdollisuuksia näkee tietenkin seuraavasti:
man ps man top
Unixmaisesta tiedostojärjestelmästä toteutuksineen puhutaan kurssilla myöhemmin lisää, mikäli ehditään. Katsotaan käyttäjän näkökulmaa tässä vaiheessa etäkoneen shellissä.
Komenna:
ls -l
Optiolla -l tiedostoja listaava ohjelma ls näyttää tiedostoista niiden nimen lisäksi lisätietoja, kuten käyttäjän ja käyttäjäryhmän, joille tiedosto kuuluu, sekä tiedoston käyttöoikeudet. Käyttöoikeudet näytetään vasemmalla puolella tulostetta, esimerkiksi seuraavasti:
-rwx--x--x. 1 nieminen nobody 9549 8.4. 13:54 a.out
Itse asiassa siitä näkyy tiedoston moodi muutenkin. Tulosteessa on 10 merkkiä, jotka ovat joko viiva - tai tietty kirjain. Viimeiset yhdeksän kertovat käyttöoikeuksista jakautuen kolmeen kolmimerkkiseen pätkään, joissa toistuvat järjestyksessä merkit r niinkuin 'read', w niinkuin 'write' ja x niinkuin 'execute'. Merkit vastaavat luku-, kirjoitus- ja suoritusoikeutta; jos merkin paikalla on viiva - niin kyseinen oikeus puuttuu. Kolmen merkin pätkät vastaavat käyttäjälle itselleen (esimerkissä käyttäjätunnus nieminen), ryhmälle (esimerkissä ryhmätunnus nobody) sekä aivan kaikille järjestelmän käyttäjille annettuja oikeuksia. Esimerkissä siis nieminen saa lukea, kirjoittaa ja suorittaa tiedostoa a.out; ryhmän nobody jäsenet saavat vain suorittaa; samoin muut kuin nieminen tai nobody -ryhmäläiset saavat suorittaa mutteivät muuta.
Oikeuksia voi muuttaa ohjelmalla chmod. Manuaali kertoo enemmän; tässä joitakin esimerkkejä:
chmod u+x TIEDOSTONIMI
Tiedoston omistajaksi merkitylle käyttäjälle (u niinkuin 'user') annetaan (+ niinkuin 'lisäys') oikeus suorittaa (x niinkuin 'execute') tiedosto, jonka nimi komennossa annetaan. Sen sijaan seuraava komento toimii päinvastoin:
chmod u-x TIEDOSTONIMI
Tässä jälkimmäisessä tiedoston omistajaksi merkityltä käyttäjältä (u niinkuin 'user') poistetaan (- niinkuin vähemmän) oikeus suorittaa (x niinkuin execute) tiedosto, jonka nimi komennossa annetaan.
Totuttele komentoon: kokeile tehdä vaikka joku humpuukitiedosto, anna ja poista sille oikeuksia ja katso kuinka ls -l -komennon tuloste muuttuu. Turvallisuuden vuoksi älä kajoa laajemmin tiedostojesi tai varsinkaan hakemistojesi käyttöoikeuksiin ennen kuin olet oppinut aiheen yksityiskohdat.
Tarkempia tietoja tiedostosta saa komennolla stat esimerkiksi seuraavasti:
stat hmm.txt
Tuloste on jotakin seuraavanlaista:
File: `hmm.txt' Size: 4 Blocks: 8 IO Block: 4096 regular file Device: fd09h/64777d Inode: 786456 Links: 1 Access: (0644/-rw-r--r--) Uid: (29067/nieminen) Gid: ( 100/ users) Access: 2014-05-05 14:56:31.509949717 +0300 Modify: 2014-04-03 16:11:07.469291072 +0300 Change: 2014-04-03 16:11:07.469291072 +0300
Jätetään mielen päälle hautumaan, että tiedostoon liittyy oikeuksien (Access) ja oikeuksiin liittyvien omistajien (Uid, Gid) lisäksi mm. aikaleimoja viimeiseen käyttöhetkeen (Access), sisällön muutoshetkeen (Modify) ja metatietojen kuten käyttöoikeuksien muutokseen (Change). Tiedoston sijaintia laajemman struktuurin sisällä ilmoittaa yksilöllinen i-solmun numero (Inode). Joihinkin näistä tiedoista palataan kurssin tiedostojärjestelmiin liittyvässä osiossa, riippuen mihin tällä kurssikerralla ehditään.
Mikä on tiedosto? Tähän mennessä varmaan ymmärretään, että se on jonkinlainen kokonaisuus, jolla on nimi, yksilöllinen osoite hakemistopuussa, omistaja, käyttöoikeuksia, pituus, aikaleimoja käyttö- ja muunteluajankohdista. Tiedosto voi sisältää esimerkiksi tekstin, kuvan, videopätkän tai suoritettavan ohjelman. Okei. Mutta miten esimerkiksi tekstitiedosto, kuvatiedosto ja suoritettava ohjelmatiedosto eroavat toisistaan?
Nyt katsotaan, miten pystyt selvittämään tasan tarkkaan, mitä tiedosto pitää sisällään. POSIX lupaa, että yhteensopivassa järjestelmässä toimii seuraava komento:
od tiedostonimi
Kokeile esimerkiksi:
od /bin/true
Tämä komento od eli "octal dump" tulosti nyt tiedoston /bin/true sisällön tasan tarkkaan siten, kuin se on, käyttäen oktaalinumeroita datan osoitteelle tiedoston alusta lukien (vasen sarake) sekä itse tiedolle (loput sarakkeet). Oktaalinumerot eivät välttämättä ole hauskin tapa katsoa tiedostoja, joten tällä kurssilla käytämme suosiolla epästandardia komentoa, joka suorakäyttökoneiltamme löytyy. Eli teemme POSIXista huolimatta seuraavaa:
hexdump -C /bin/true | less
(Muistat varmasti (?), että less näyttää putken vasemmalla puolella olevan komennon tulosteen vähän kerrassaan ja siten, että tulostetta voi selata edestakaisin.)
Tämä hexdump, kun sille antaa argumentin -C ja jonkin tiedoston osoitteen, niin se näyttää tiedoston sisällön kohtalaisen nätissä formaatissa, joka alkaapi tässä tapauksessa seuraavalla tavoin:
00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............| 00000010 02 00 3e 00 01 00 00 00 70 0f 40 00 00 00 00 00 |..>.....p.@.....| 00000020 40 00 00 00 00 00 00 00 20 5a 00 00 00 00 00 00 |@....... Z......| 00000030 00 00 00 00 40 00 38 00 08 00 40 00 20 00 1f 00 |....@.8...@. ...| ...
Vasemmalla on datan sijaintipaikka heksalukuna tiedoston alusta alkaen. Sitten on aina 16 kappaletta 8-bittisiä tavuja ja lopussa vielä sarake, jossa nämä 16 tavua on tulostettuna, mikäli ne sattuvat olemaan "selväkieliseen" ASCII-merkistön osuuteen kuuluvia eli "tulostettavia ('printable')" merkkikoodeja.
Tässä tapauksessa, kuten aika usein, tiedoston ensimmäisistä tavuista voi päätellä paljon siitä, mitä tiedosto pitää sisällään. Tässä tapauksessa ensimmäiset tavut ovat heksana 7f 45 4c 46, mihin sisältyvät numerokoodit 0x45, 0x4c ja 0x46 voidaan tulkita ASCII-merkistön mukaan merkkijonoksi ELF. Tiedosto ei todennäköisesti liity pitkäkorvaisiin haltioihin tai tonttuihin (engl. "elves", yksikkö "elf"), vaan mitä todennäköisimmin se sisältää ELF-muotoon tallennettua konekielistä ohjelmakoodia (ELF == "Executable and Linkable Format).
Voit selailla tiedostoa edestakaisin less-ohjelmassa nuolilla ja PageUp, PageDown -näppäimillä ja katsella, löytyykö sen sisältä mahdollisesti muitakin lukukelpoisia tekstejä. Olennaista on, että nyt tiedät, miten pystyt katsomaan tavu tavulta, bitti bitiltä, mitä mikäkin tiedostosi pitää sisällään. Voit huvikseen tutkia, miltä tietokoneen mielestä näyttävät esim. tekstitiedostot, kuvatiedostot, docx-dokumenttitiedostot, zip-paketit... (kahdessa viimeksimainitussa on jotakin yhteistä, muuten).
Työkaluohjelma file kokeilee heuristisesti, mikä tiedoston todennäköinen formaatti on:
file /bin/true
Kun on selvinnyt, että tämä /bin/true on ohjelmatiedosto, voidaan sen sisältöä tarkastella myös seuraavasti:
objdump -x /bin/true | less
Tulosteessa on kaikenlaisia toistaiseksi enemmän tai vähemmän mystisiä tekstejä ja heksanumeroita; jätetään toistaiseksi hautumaan.
(Reunahuomautuksena... tämä true -ohjelma on POSIX-standardin edellyttämä apuohjelma, joka manuaalin mukaan "ei tee mitään, onnistuneesti", tarkista vaikka komennolla man true... Se on siis vähän niinkuin jotkut meidän opiskelijat, mutta et Sinä, koska olet ilmeisesti tekemässä tätä demoa, mikä on enemmän kuin ei mitään...)
"Emacs tai Vim - muuten ei ole nörtti"
(lentävä lause henkilökunnan kahvihuoneessa; alkuperä tuntematon)
Normaaliolosuhteissa käytämme ohjelmakoodin ja järjestelmäylläpidon tehtäviin työpaikan tarjoamia tai itse hankittuja graafisia työkaluja, joihin mm. IDEt ja tekstieditorit lukeutuvat. Materiaalit kehitetään ja testataan lokaalisti, ylläpidetään jaetussa versionhallinnassa ja testatut tuotantoversiot jaellaan aikataulun mukaisesti asiakkaille. Monien nykyisten tuotteiden tapauksessa tämä tarkoittaa asiakkaan tuotantopalvelimessa toimivan palvelinohjelmiston päivittämistä.
Joskus tarvitsee hätätilanteessa (tai siksi että se on vaan nopeampaa kuin kopioida tiedostoja edestakaisin) tehdä jotakin ylläpitotoimenpiteitä suoraan pääteyhteydellä tekstieditorilla, jossa ei ole graafista käyttöliittymää. Mm. näitä tilanteita varten tällä kurssilla totutellaan tekstieditointiin päätteellä. Kehittyneempien tekstieditorien käyttöliittymät on myös kehitetty lähtökohtaisesti erinomaisen tehokkaiksi. Modernimmissa IDEissäkin on usein mahdollista säätää asetuksista näppäinkomennot vastaamaan "vanhojen kunnon" tekstieditorien tyyliä, jolloin mm. ei tarvitse juurikaan siirtää käsiä näppäinten keskeltä hiirelle, eikä edes nuolinäppäimillekään asti! Tekstin tuottaminen ja siirtely paikasta toiseen voi tällöin tulla huomattavan paljon nopeammaksi toimenpiteeksi kuin ajattelu, jota ohjelmien luominen tietysti ensisijaisesti vaatii.
Alkupuolella tätä demoa nähtiin nano, joka on helppokäyttöinen, mutta jossa ei oikeastaan paljon muita ominaisuuksia ole. Oikeasti tekstin editointi vaatii järeämpää kalustoa.
POSIX-standardi määrää, että yhteensopivasta järjestelmästä löytyy vähintään yksi "visuaalisesti orientoitunut" tekstieditori, joka käynnistyy komennolla vi ja toimii aina vähintään juuri tietyllä tapaa. Käytännössä nykyään esim. meidän suorakäyttökoneillamme tuo komento käynnistää laajennetun editorin nimeltä vim eli "Vi IMproved". Vim on hyvin käyttökelpoinen ja tehokas tekstieditori, mutta sen käyttöönotossa on jonkin verran jyrkempi oppimiskäyrä kuin nano:ssa.
Toinen hyvin kehittynyt ja tehokas tekstieditori on emacs, jonka saa helposti asennettua moniin unixmaisiin käyttöjärjestelmiin - esimerkiksi meidän suorakäyttökoneillamme se löytyy valmiiksi asennettuna.
Jos aikasi on todella rajallinen, riittää hätätilanteessa käyttää nanoa, jolla pystyy tekemään tämän sekä myöhemmät tämän kurssin demot, vaikkakaan ei kovin tehokkaasti.
Pidemmän päälle suositeltavaa (ehkä jopa ajankäytön suhteen) on valita joko vim tai emacs ja perehtyä sen ominaisuuksiin yksi kerrallaan. Tämän demon kirjoittajan oma suosikki on ilman muuta emacs, mutta sotien välttämiseksi tuli nyt tälläkin kertaa mainittua vim ensiksi.
Keväällä 2016 näitä demoja on tekemässä myös syventävän kurssin "Linux-palvelimen ylläpito" opiskelijoita. Heille suosittelen vimiä, koska se löytyy emacsia useammin palvelimilta. Kyseinen porukka myös unohtakoon sen nanon ihan suosiolla!
Lopuksi mainittakoon automaattinen tekstieditointi, joka voi joskus tarjota nopeimman ja helpoimman keinon etsi- ja korvaa -tyylisiin tai muihin mekaanisiin tekstinkäsittelytehtäviin. Tyypillisiä työkaluja ovat ainakin POSIX-standardin vaatimat sed ja awk. Näihin tuskin ehditään perehtyä tällä kurssilla ainakaan muutamaa esimerkkiä pidemmälle. Idea on, että näillä työkaluilla voi etsiä ja korvata merkkijonon kerralla vaikka 10000 tekstitiedostosta, joissa on yhteensä teratavu materiaalia. Käsipelillä menisi ikuisuus ja esim. usean gigatavun kokoista tekstitiedostoa tuskin pystyisi edes avaamaan tekstieditorissa.
Nanon käynnistäminen käytiin läpi tämän demon alussa. Melkein kaikki toiminnot näkyvät ruudun alalaidassa. Control-näppäimen painaminen kirjoitetaan lyhyesti väkäsellä eli sirkumfleksilla, esim. ^G tarkoittaa samaa kuin näppäily Ctrl-g. Kyseinen näppäilyhän antaa tarkemman ohjesivun, jonka perusteella varmaan pärjäät tarvittaessa.
Huomionarvoinen lisätarkennus liittyy useamman peräkkäisen rivin kopiointiin: Mene riville, josta alkaa haluamasi kopioitava pätkä. Sitten tuhoa ("kill") Ctrl-k:ta painamalla peräkkäisiä rivejä niin paljon kuin haluat lopulta kopioida. Peräkkäin tuhotut rivit tallentuvat itse asiassa tuhoamispuskuriin ("kill buffer"), jonka saat takaisin näppäilemällä Ctrl-u ("un-kill"(?)). Mene kohtaan, johon haluat laittaa kopion ja näppäile toisen kerran Ctrl-u. Kopio on valmis ja voit editoida sitä eteenpäin.
Ohjelmakoodia on paljon helpompi editoida editorilla, joka tukee syntaksin mukaista värikoodausta. Jopa nanossa jonkinlainen köpsähtävä perustuki onneksi löytyy. Ohjeet värityksen käyttöön nanossa annetaan C-kielen editointia edellyttävän demon yhteydessä.
Toivottavasti uskaltaudut kuitenkin edes hiukan kokeilemaan jompaa kumpaa tehokkaammista editoreista, vaikka niiden oppimiskäyrä on aluksi jyrkempi.
Emacs -tekstieditorin ensimmäinen versio on peräisin vuodelta 1976. Kuinka hyväksi spesifiin tarkoitukseen tehty ohjelmisto voi kehittyä 40 vuodessa, kuten emacs vuoteen 2016 mennessä? Vinkki: aika hyväksi. Vuonna 2015 meidän suorakäyttökoneellemme on asennettu versio "GNU Emacs 23.1.1". Lisätietoa emacsista esim. wikipedia http://en.wikipedia.org/wiki/Emacs ja virallinen sivu https://www.gnu.org/software/emacs/
Tämä editori käynnistyypi komennolla:
emacs
Ensimmäisellä käynnistyskerralla emacs havaitsee, ettet ole aiemmin käynnistänyt sitä, ja tarjoilee ohjeita. Ota vastaan, jos siltä tuntuu. Tässä demolapussa pystytään antamaan vain kriittisimmät selviytymisohjeet. Oletusasennuksessa emacs tunnistaa 2000 erilaista komentoa, ja siihen voi ohjelmoida lisää ominaisuuksia miten tahtoo... valmiita lisälaajennuksia on netti pullollaan.
Selviytyminen, osa 1: Emacsin saa suljettua näppäilemällä Ctrl-x Ctrl-c eli ensin Control ja x-näppäin ja sen perään Control ja c. Muistaakseni on ihan kiva tietää, miten ohjelman saa suljettua.
Selviytyminen, osat 2 jne: Emacsissa voi olla auki monta tiedostoa yhtä aikaa niin sanotuissa "puskureissa". Paljolti perustoiminnot perustuvat yhden tai parin näppäimen näppäinyhdistelmiin, jotka laukaisevat toimenpiteitä. Melkein jokainen näppäimen painallus laukaisee erikseen ohjelmoitavissa olevan toiminnon, yksinkertaisimmillaan vastaavan merkin lisäämisen näkyvissä olevaan puskuriin osoittimen kohdalle.
Emacsissa on oma tutoriaali, jonka saa päälle näppäilemällä Ctrl-h t. Ohje koostuu tekstitiedostosta, joka avautuu suoraan editoriin itseensä ja käytännön tekemisen kautta opastaa alkuun.
Esimerkkinä joitakin aivan yksinkertaisimpia komentoja suomeksi kuvattuna tässä:
Loput 2000+ komentoa eivät mahdu tähän ohjeeseen; lisää manuaalissa https://www.gnu.org/software/emacs/manual/html_node/emacs/index.html ja lukuisissa tutoriaaleissa, joita voi etsiä Internetistä vaikkapa hakusanalla "emacs tutorial".
Myös vi -editorin ensimmäinen versio on julkaistu vuonna 1976. Toistetaan siis kysymys, että kuinka hyväksi spesifiin tarkoitukseen tehty ohjelmisto voi kehittyä 40 vuodessa, kuten vi vuoteen 2016 mennessä? Tähän vastaus on sama kuin emacsin suhteen. Vinkki: aika hyväksi. Alkuperäinen vi on myös standardoitu POSIXissa. Matkan varrella, vuosina 1987-1993, syntyi nykyisin suosittu laajennettu, eikä täysin standardin mukainen "Vi IMproved", joka esimerkiksi meidän suorakäyttökoneiltamme löytyy. Lisätietoa esim. wikipediasta http://en.wikipedia.org/wiki/Vim_%28text_editor%29 ja Vimin omilta sivuilta http://vim.sourceforge.net/ .
Selviytyminen, osa 1: Vimin saa suljettua suljettua näppäilemällä ESC : q ! Enter. ESC siirtää vimin tilaan, joka odottaa komentoja, jos se oli vahingossa jossain muussa tilassa. Sitten annetaan komento :q ("q"==quit) ja kirjoitettu komento kuitataan enterillä. Jos on tallentamattomia muutoksia joita ei haluta säilyttää, niin loppuun pitää laittaa vielä huutomerkki ! ("!"=="tosissaankin").
Selviytyminen, osat 2 jne: Vimissä on erikseen komentotila (normaalitila) ja kirjoitustila, ja lisäksi on muita tiloja erityistarpeeseen, kuten "visuaalinen tila" tekstin maalaamiseen ja leikkaamiseen leikepöydälle. Idea on tehdä tekstin poistot, leikkaamiset, liimaamiset ynnä muut muutokset komentotilan kautta, ja kirjoittaa uutta tekstiä tarvittaessa kirjoitustilassa. Kirjoitustila menee päälle esim. näppäilyllä i ("i"==insert). Kirjoitustilasta pääsee takaisin komentotilaan näppäilemällä ESC.
Varoitus: Kun mahdollisesti leikkaat jostain tekstiä ja liimaat sen pääteyhteydessä, niin ole varovainen (myös) Vimin kanssa. Jos vim on komentotilassa, niin pääteikkunaan copy-pastettua tekstiä käsitellään tietysti merkki kerrallaan kuin komentoja, mikä saattaa aiheuttaa virheiden ilmaantumista, pahimmillaan editoitavan tekstin muuttumista, häviämistä ja Vimin asetusten muuttumista!
Vimillekin löytyy sen oma pika-tutor, jonka saa suorakäyttökoneella käyntiin komennolla:
vimtutor
Ohje koostuu tekstitiedostosta, joka avautuu vim -editoriin. Kyseinen ohje lupaa opettaa Vimin peruskäytön puolessa tunnissa. Kokeilin itse, ja näin siinä voi käydä. Eli ajankäytön suhteen kumminkin aika minimaalista suhteessa loppuelämäksi saatavaan hyötyyn.
Vim jakaantuu erilaisiin tiloihin, jolloin tälläiseen ajattelutapaan tottumaton käyttäjä hämmentyy aluksi, koska aiemmin tutuissa graafisissa editoreissa tällaista toimintamallia ei ole. Esimerkiksi komentotilassa näppäily x hävittää osoittimen alla olevan merkin. Toki sen saa takaisin näppäilemällä u niinkuin "undo". Vim (kuten emacskin) on suunniteltu nopeaksi editoriksi. Oikein käytettynä tekstin muokkaaminen on todella tehokasta, mutta aluksi sen opettelu mahdollisesti vaatii graafisia kollegoitaan enemmän aikaa ja vaivaa.
Tarkkaile ettei Caps-Lock ole vahingossa jäänyt päälle kun käytät normaalitilaa. Isoilla kirjaimilla on tässä väliä. Tiettyjä aloittajalle riittäviä komentoja:
a siirtyy lisäystilaan kursorin oikealle puolelle. A siirtyy lisäystilaan nykyisen rivin loppuun. i siirtyy lisäystilaan kursorin kohdalle. I siirtyy lisäystilaan rivin nykyisen alkuun. h,l liikkuu vasemmalle, oikealle. Rivin alussa/lopussa ei siirrytä automaattisesti toiselle riville! j,k siirtyy seuraavalle, edelliselle riville. u palauttaa muutoksista, "undo" x poistaa kursorin kohdalla olevan merkin. 0 (numero nolla) siirtää kursorin rivin alkuun. $ (dollarimerkki) siirtää kursorin rivin loppuun. o,O Luo uuden rivin nykyisen rivin alapuolelle, yläpuolelle. Siirtää kursorin sinne lisäystilassa. w,e siirtää kursorin seuraavan sanan alkuun, loppuun. : siirtyy Vimin komentoriville. Pois pääsee painamalla askelpalautinta tai ESC näppäintä. v siirtyy visuaaliseen-/valintatilaan.
Osaan edellisistä komennoista saa lisämausteita kirjoittamalla numeroita ennen komentoa, esim. 3j siirtyy kolme riviä alemmaksi.
Valintatilassa editori näyttää kursorin ja sen paikan välisen alueen korostettuna, jossa kursori oli valintatilaan siirryttäessä, jolloin tämän korostetun alueen voi vaikka kopioida tai poistaa. Valintatilassa painamalla y editori kopioi korostetun alueen, painamalla d leikkaa sen (poistaa samalla kun kopioi). Täten leikepöydälle kopioidun alueen voi liimata uuteen paikkaan näppäilyllä p.
Vim on monipuolinen editori, josta löytyy kasa muitakin tiloja sekä komentoja, oma skriptikieli sekä monia muita herkkuja.
Joidenkin mielestä emacs on paras, joidenkin mielestä vim. Molemmat on tekstin editointiin riittäviä, mutta jompikumpi on osattava, että voi osallistua keskusteluun :).
Molemmat editorit ovat kokeneen käyttäjän käsissä luultavasti tehokkain toistaiseksi keksitty tapa siirtää tekstiä henkilön pään sisältä tietokoneelle.
Molempien ero esim. nano -editoriin tai Windowsin notepad -editoriin on suurin piirtein sama kuin Boeing 777:n ero paperilennokkiin.
TODO (ei vielä 2015 eikä 2016): Ihan muutama esimerkki siitä, miten search&replace ym. hoituu automaattisesti esimerkiksi POSIXin määräämiä apuohjelmia sed ja awk käyttäen.
Varioidaan ensimmäisessä demossa tehtyä palautustehtävää. Tällä kertaa automatisoidaan toimenpide, eli tehdään tekstieditorilla noin seitsemän riviä pitkä shell-skripti, joka tuottaa halutunlaisen tulosteen.
Tiedoston muodon tulee olla seuraavanlainen (huomaa pienet erot demossa 1 tehtyyn):
Mikä ja miksi on skripti? Skripti (engl. script) eli "komentojono" tai "komentoriviohjelma" on shellin, esimerkiksi bashin, ymmärtämän syntaksin mukainen ohjelma, jonka shell lukee, tulkkaa ja suorittaa rivi riviltä. Laajemmin ajateltuna skriptiksi voitaisiin sanoa millä tahansa tulkattavalla kielellä (esim. python, perl, lua, php, matlab, ...) tehtyä ohjelmaa, mutta käyttöjärjestelmien mielessä kiinnostavaa on tietysti juuri käyttöjärjestelmäkuorella eli shellillä ajettavat skriptit esimerkiksi käyttöjärjestelmän ylläpitotehtävien (käynnistys ja alasajo, logit, päivitykset, varmuuskopioinnit, ...) hoitamiseen.
Yksinkertaisimmillaan skripti koostuu peräkkäisistä komennoista, joita voisi yhtä hyvin kirjoittaa ja suorituttaa interaktiivisesti peräkkäin. Skriptiin kirjoitettuna ne jäävät kuitenkin talteen mahdollista myöhempää uudelleenkäyttöä varten. Useamman suoritettavan komentorivin kirjoittaminen on joka tapauksessa helpompaa ja vähemmän virhealtista tekstieditorilla kuin suoraan interaktiivisesti. Shell-skriptit voivat myös ottaa normaalien ohjelmien tapaan argumentteja, ja niihin voidaan kirjoittaa normaaleja ohjelmointirakenteita kuten muuttujia, aliohjelmia, silmukoita ja ehtoja. Shell-skriptit ovat todellinen järjestelmäylläpitäjän tehotyökalu.
Aloitetaan harjoitteet yksinkertaisesta päästä: Käytä valitsemaasi tekstieditoria yhdessä screen -ohjelman tarjoamassa ikkunassa ja kirjoita peräkkäisille riveille ylläolevassa tehtäväkuvauksessa tarvittavat komennot. Käytä toista screen -ohjelman tarjoamaa ikkunaa skriptin kokeilemiseen ja tulosteen oikeellisuuden tarkastamiseen.
Ensimmäisellä rivillä skriptissä tulee ilmoittaa risuaidan ja huutomerkin jälkeen shell-ohjelman eli meidän esimerkeissämme bashin sijainti tiedostojärjestelmässä. Skriptisi tulee siis alkamaan jotakuinkin näin:
#!/bin/bash whoami > kj16_demo2_tuloste.txt ...
Huomaa, että tiedoston kj16_demo2_tuloste.txt aiempi sisältö häviää, kun ohjataan tuloste väkäsellä. Jatkaminen edellisen sisällön perään edellyttää kahden väkäsen käyttöä. Välilyönnit tulkitaan erotinmerkeiksi jne., joten ole edelleen perusvarovainen ja koeta etukäteen hahmottaa mitä suorituksissa tapahtuu.
Tulevassa (mahdollisesti vapaaehtoisessa) demossa opetellaan tekemään toimintavarmempia ja turvallisempia skriptejä, joille voi antaa kohdetiedoston nimen argumenttina ja jotka kieltäytyvät tekemästä tuhoisaa toimenpidettä, jos kohdetiedosto on jo olemassa. Mutta ei sekoiteta päätä vielä sillä, vaan kovakoodataan tuo tulostetiedoston nimi vaikkapa juuri kj16_demo2_tuloste.txt.
Skripti pitää ajaa oleskeluhakemistosta, eli komentamalla:
./demo2_skripti.sh
Tätä varten tiedoston käyttöoikeuksiin pitää lisätä suoritusoikeus käyttäjälle itselleen. Käytä siis komentoa chmod sopivasti. Älä lisää muita kuin välttämättömät oikeudet! Tässä vaiheessa tarvitset vain suoritusoikeuden käyttäjälle.
Kokeile skriptiä yhdessä screen-ikkunassa ja katso, että tuloste vastaa speksiä, esim:
cat kj16_demo2_tuloste.txt
Editoi tarpeen mukaan skriptiäsi siinä screen-ikkunassa, jossa editori on auki. Keskustele tarvittaessa ircissä kolmannessa screen-ikkunassa...
Tulostetiedoston lopussa halutaan vielä tehtävän tarkastamisen yhteydessä nähdä itse skriptin sisältö. Tämä hoituu sillä, että skriptisi viimeinen rivi on TÄSMÄLLEEN seuraava:
cat $0 >> kj16_demo2_tuloste.txt
Tätä älä toistaiseksi modaa mitenkään. Myöhemmin kurssilla selviää, millaisia potentiaalisia ongelmia tällä voisi vahingossa saada aikaan. Tämä valmiiksi annettu viimeinen rivi ohjaa kohdetiedoston perään cat -ohjelman tulosteen. Catille on annettu argumentiksi $0, joka skriptiä ajettaessa korvautuu komennolla, jolla skripti itse on suoritettu eli komennoksi muodostuu tässä oikeastaan automaattisesti cat ./demo2_skripti.sh >> kj16_demo2_tuloste.txt. Lopputulemana kirjoittamasi skriptin sisältö siis tulostuu tulostiedoston perään. Dollarimerkillä alkavista jutuista puhutaan myöhemmin lisää. (En tiedä, onko $0:n käyttö tässä standardin mukaista, mutta meidän yhteisessä toimintaympäristössä saadaan nyt tällä tavoin yhteen tarkastettavaan tiedostoon kaikki tarvittava eli tulosteet, joista nähdään, että screen-ohjelmaa ja tekstieditoria on oltu käyttämässä yhtäaikaa sekä myöskin itse tekemäsi skripti, jolla tuloste on luotu; irssin näkymisestä prosessilistauksessa respectiä, vaikka sitä ei tämän demon puitteissa vaaditakaan).
Keväällä 2016 kurssin demot ja niiden palautus hoidetaan osoitteessa itka203.it.jyu.fi olevan järjestelmän kautta. Kullekin demolle on oma palautuslaatikko, johon tehtävässä tuotettu tiedosto palautetaan.
Tästä demosta palautetaan tasan yksi tiedosto nimeltään "kj16_demo2_tuloste.txt", joka on luotu edellisessä kohdassa kuvatulla tavalla.