Työkaluajattelu Unix-filosofiassa,
esimerkkinä säännöllinen varmuuskopiointi Linuxissa

Tämä kirjoitus kertoo erään tavan tehdä säännöllisiä varmuuskopioita Linuxissa. Samalla teksti on johdatus työkaluajatteluun, jonka ymmärtäminen on tärkeä osa Unix-tyyppisten järjestelmien toiminnan ymmärtämistä.

Tehtävä: Oletetaan Linux-järjestelmä, jossa normaalista varmuuskopioinnista on jo huolehdittu, esimerkiksi viikoittain tehdään nauhavarmistus. Lisätään toiminto, jolla joka yö kotihakemistojen muuttuneista tiedostoista tehdään varmuuskopio, ja kopioita säilytetään viikon ajan. Oletetaan lisäksi, että kone on aina käytössä, ja että /mnt/varalevy/ sisältää riittävästi tilaa varmuuskopioille.

Esimerkit on testattu Red Hat Linuxin versiossa 6.2, mutta toimivat pienin muutoksin paitsi toisissa Linux-jakelupaketeissa, myös muissakin Unix-tyyppisissä käyttöjärjestelmissä.

Sisällys

tar ja gzip:Tiedostot tiiviisti yhteen

Tiedostot yhdistetään tar-komennolla. Esimerkiksi tiedostot kissa.txt ja koira.txt yhdistetään tiedostoksi elukat.tar näin:
 tar cf elukat.tar kissa.txt koira.txt
Näin tehty paketti avataan komennolla
 tar xf elukat.tar
Pelkästään listan paketin tiedostoista tulostaa komento
 tar tf elukat.tar
Paketin nimen loppuosa .tar on yleinen tapa, mutta ei sääntö. tar osaa pakata kokonaisia hakemistoja alihakemistoineen. Villen tekstit pakataan vaikkapa sanomalla
 tar cf /mnt/varalevy/villenjutut.tar /home/ville/tekstit
Komento olettaa, että /mnt/varalevy on hakemisto, johon varmuuskopio mahtuu.

Tiedosto pakataan gzip-komennolla. Esimerkiksi
 gzip elukat.tar
luo tiedoston elukat.tar.gz, joka puretaan komennolla
 gunzip elukat.tar.gz

Putki: toisen syöte on ensimmäisen tuloste

Edellä tehtiin tarpeeton väliaikaistiedosto. Tämän vältät näin:
 tar cf - kissa.txt koira.txt | gzip -c > elukat.tar.gz
Jokaisella on ohjelmalla on standarditulostevirta, joka yleensä tulostetaan näytölle, sekä standardisyötevirta, joka yleensä luetaan näppäimistöltä. Edellisessä komennossa oleva '|' on putkimerkki. Se tarkoittaa, että merkin vasemmanpuoleisen komennon standarditulostevirta ohjataan oikeanpuoleisen komennon standardisyötevirraksi. tar-komennossa tiedoston nimen paikalla oleva viiva tarkoittaa, että tiedoston sijasta pakattu data ohjataan standarditulostevirtaan. gzip-komennon -c -valitsimella on sama tarkoitus. '>' -merkki ohjaa tulostevirran tiedostoon.

Esimerkin ymmärtää ehkä helpommin vertaamalla komentoa
 cal | sort
kolmeen erilliseen komentoon
 cal > tilapainen_tiedosto
 sort tilapainen_tiedosto
 rm tilapainen_tiedosto
(cal tulostaa kalenterin, sort järjestää rivit aakkosjärjestykseen ja rm poistaa tiedoston.)

Linuxissa yleensä käytettävä versio tar-komennosta osaa itsekin kutsua gzip-ohjelmaa. Tarvittava lisäys on yksi z-kirjain:
 tar czf elukat.tar.gz kissa.txt koira.txt
yhdistää tiedostot ja pakkaa lopputuloksen. Paketti puretaan komennolla
 tar xzf elukat.tar.gz

find: tiedostojen etsiminen

find-komennolla voit etsiä tiedostoja erilaisten ehtojen mukaan. Komennon yleinen muoto on
 find aloitushakemisto ehto mitätehdään
Esimerkiksi /home/ville/tekstit -hakemistosta etsitään .txt -merkkeihin loppuvia tiedostoja näin:
 find /home/ville/tekstit -name "*.txt" -print
find-komento etsii tiedostoja kaikista alihakemistoista (ls *.txt näyttää vain yhden hakemiston tiedostot). -print kertoo mitä tehdään löydetylle tiedostolle, eli tässä tapauksessa tulostetaan tiedoston nimi. Hakemistoksi voi usein antaa pelkän pisteen, joka tarkoittaa nykyistä työhakemistoa.

Varmuuskopioinnissa tärkeä ehto on viimeinen muokkausaika. Ehto annetaan vuorokausina -mtime -vivulla tai minuutteina -mmin -vivulla. Esimerkiksi puolen tunnin sisällä muokatut tiedostot löydät sanomalla
 find . -mmin -30 -print
-30 tarkoittaa korkeintaan 30 minuutin aikana muokattuja tiedostoja, vastaavasti +30 olisi yli 30 minuuttia ja 30 tarkoittaisi tasan 30 minuuttia sitten muokattuja tiedostoja.

Kun hakemistoon lisätään tiedosto, niin hakemiston muokkauspäivämäärä muuttuu. Tietenkään koko tekstit-hakemistoa ei haluta varmuuskopioida pelkästään yhden lisätyn tiedoston vuoksi. Onneksi find-komento tuntee myös vivun, jolla määrätään tiedoston tyyppi. Tavalliset tiedostot löytyvät komentamalla
 find . -type f -print

xargs: tiedostojen nimet toiselle komennolle

xargs-komento lukee putkesta tai näppäimistöltä tiedostonnimiä ja antaa ne jonkun toisen komennon käsiteltäväksi. Kokeile komentoa
 xargs tar cf elukat.tar
ja kirjoita tiedostonimet 'kissa.txt' ja 'koira.txt' eri riveillä ja lopeta kirjoittaminen Ctlr-D -näppäilyllä. Tulos on täsmälleen sama kuin tämän kirjoituksen ensimmäisessä esimerkissä.

Yleensä xargs-komento tulee putkimerkin oikealle puolelle. Esimerkiksi kaikkien .txt-loppuisten tiedostojen sisältö tulostuu näin:
 find . -name "*.txt" -print | xargs cat
Tässä ensimmäinen komento tulostaa listan tiedostojen nimistä, ja xargs sitten tekee näistä komennon cat tiedosto1.txt tiedosto2.txt ... (cat tulostaa tiedoston.)

Välilyönnit tiedostojen nimissä

Edelläolevassa on vielä pieni ongelma. Välilyöntiä käytetään erottamaan tiedostoja ja komennon osia toisistaan, mutta myös tiedoston nimi voi sisältää välilyöntejä. find-komento kyllä tulostaa kiltisti "Kirje Liisalle.txt", mutta xargs-komennon käynnistämä komento etsiikin tiedostoja "Kirje" ja "Liisalle.txt".

Ratkaisu on ensinnäkin käyttää find-komennon mitä tehdään -osassa valitsinta -print0, jolloin tiedostojen nimet erotellaan toisistaan rivinvaihdon sijaan nollamerkillä. Toiseksi xargs -komennolle pitää antaa valitsin -0, jolloin sekin käyttää erottimena nollamerkkiä.

Nyt pääsemme lähes tavoitteeseen:
 find /home -mtime -1 -type f -print0  | xargs -0 tar czf /mnt/varalevy/homet.tar.gz
(Komento tulee yhdelle riville riippumatta siitä, monellako rivillä se yllä näkyy.) Ensin find-komento etsii jokaisen tiedoston, joka sijaitsee hakemistossa /home, jota on muutettu korkeintaan vuorokauden sisällä ja joka on normaali tiedosto eikä esimerkiksi hakemisto. Nämä tiedostojen nimet kirjoitetaan putkeen. xargs lukee putkea ja luo tar-komennon, joka saa argumentteinaan tiedostojen nimet.

Ajastetut komennot

Hakemistossa /etc on alihakemistot cron.hourly, cron.daily, cron.weekly ja cron.monthly. Jatkuvasti toimiva ohjelma crond lukee tiedostoa /etc/crontab ja tämän tiedoston sisällön perusteella tekee joitakin asioita säännöllisin väliajoin. Yleensä crontab sisältää vain rivit, joilla edellämainittujen alihakemistojen sisältämät ohjelmat ajetaan tiettyinä aikoina.

Ajastusta voi kokeilla luomalla hakemistoon /etc/cron.hourly tiedoston aika, jonka sisältönä on vain yksi rivi:
 date >> /root/ajat
ja antamalla tiedostolle suoritusoikeuden:
 chmod u+x aika
Tästä eteenpäin kerran tunnissa (luultavasti hieman yli tasatunnein) ajetaan tiedosto /etc/cron.hourly/aika, joka kirjoittaa tiedoston /root/ajat loppuun kellonajan. (Pelkkä > poistaa tiedoston entisen sisällön, >> lisää tiedoston loppuun tekstiä standarditulostevirrasta.)

Varmuuskopion nimeen viikonpäivä

date-komennolla voit tulostaa päiväyksen ja kellonajan monessa eri muodossa. Tässä kiinnostava muoto on date +%a, joka tulostaa viikonpäivän lyhenteen, esimerkiksi tiistaina vaikkapa "Tue" tai "ti", maa-asetuksista riippuen. Komennon tuloste saadaan tiedoston nimen osaksi ` -merkillä näin:
 echo moro > `date +%a`.txt

Tämän tekstin ensimmäisessä versiossa oli esimerkki
 echo moro > `date | head -c 3`. txt
Komento on tarpeettoman monimutkainen ja olettaa viikonpäivän lyhenteen olevan kolmikirjaiminen. Muotonsa puolesta se kuitenkin on virheetön, yläpilkkujen sisällä oleva komento voi olla putkitettu. Yleensäkin eri toimintoja voi yhdistellä vapaasti.

Loppuratkaisu

Lopullinen ratkaisu on pari komentoa ja kolmen rivin tiedosto. Tee hakemistoon /etc/cron.daily seuraava tiedosto (Viimeinen rivi on tässä teknisistä syistä katkaistu. Kirjoita se itse samalle riville.)


 #!/bin/bash
 rm /mnt/varalevy/vara-`date +%a`.tar.gz
 find /home -mtime -1 -type f -print0 | xargs -0 tar
 czf /mnt/varalevy/vara-`date +%a`.tar.gz

ja anna sille suoritusoikeus chmod-komennolla. Ensimmäinen rivi, "#!/bin/bash", ei ole välttämätön, mutta siitä on helppo tunnistaa tiedoston tyyppi.

Pohdintaa helppoudesta ja vaikeudesta

Windows-maailmaan tottuneesta Linuxin/Unixin tapa tehdä asioita voi tuntua järjettömän vaikealta. Miksei ole graafista työkalua, jossa hiiren napsautuksilla voi määrätä varmuuskopioinnin aikataulun yms? Itse asiassa sellainenkin luultavasti on, ja ellei ole, on tekeminen aika helppoa. Graafinen työkaluhan voi teettää varsinaisen työn tässä kuvatuilla komennoilla.

Toisaalta ei voi sanoa, että Linuxin käyttö olisi vaikeaa. Sen opiskelu sitä kyllä usein on. Mutta kun olet oppinut tässä käsitellyt asiat, voit esimerkiksi ohittaa tiettyjen tiedostojen varmuuskopioinnin sopivilla find-komennon valitsimilla.

Työkaluajattelu mahdollistaa äärimmäisen joustavuuden. MP3-musiikkia soittavaa ohjelmaa voi käyttää herätyskellona, mutta ohjelman tekijän ei tarvitse vaivata tällä päätään, kaikki ohjelmathan voidaan suorittaa ajastetusti. Käyttäjä voi yhdistää ohjelmia luovasti, ei ohjelmoijan ennalta määräämillä tavoilla. Voi vaikka soittaa viimeisen viikon aikana luodut MP3-tiedostot sopivaa find-käskyä käyttäen.

Karu totuus: ei tämä toimikaan (aina)

Kirjoitettuani tämän tekstin kysyin kommentteja ja huomasin, että tekstissä on monia ongelmia. Toisaalta tämäkin on omalla tavallaan opettavaista, joten en muokkaa edelläolevaa, vaan luettelen tässä ongelmakohdat.

Linuxissa on joitakin teknisiä rajoituksia eri asioille. Ensinnäkin tiedostojen koko on rajoitettu kahteen gigatavuun (Myöhempi lisäys: Rajoitus on poistunut uudempien ytimen versioiden myötä). Liian iso varmuuskopio yksinkertaisesti katkeaa kesken.

Yllättävämpi rajoitus tulee komentorivin pituudesta. xargs muodostaa joskus hyvinkin pitkän komennon, ja komentorivin maksimipituus Red Hat 6.2:n asennuksen jälkeen on hieman yli 100 kilotavua. Jos varmistetaan tuhat tiedostoa, ja keskimääräinen nimen ja polun yhteispituus on sata merkkiä, raja tulee täyteen. Tällöin xargs suorittaa tar-komennon monta kertaa, ja joka kerta tar kirjoittaa tiedoston uudelleen. Tuloksena ei siis ole virheilmoitusta, vaan .tar.gz-paketti, jossa on vain osa halutuista tiedostoista!

Korjaus on esimerkiksi luoda ensin find-komennolla lista tiedostoista näin:
 find /home -mtime -1 -type f -print > /mnt/varalevy/lista.txt
ja käyttää tar-komennon muotoa, joka lukee varmistettavien tiedostojen nimet tekstitiedostosta:
 tar czf /mnt/varalevy/vara-`date +%a`.tar.gz -T /mnt/varalevy/lista.txt
Toinen vaihtoehto on putkittaa tämä komennoksi
 find /home -mtime -1 -type f -print | tar czf /mnt/varalevy/vara-`date +%a`.tar.gz -T  -
(Kirjoita komento yhdelle riville, vaikka se yllä voikin jakautua eri riveille.) tar-komennon vipu -T siis lukee tiedostosta varmistettavat tiedostot, ja pelkkä '-' nimenä tarkoitaa standardisyötevirtaa (joka saadaan taaskin putkella find-komennon standarditulostevirrasta).

Maa-asetuksetkin voivat yllättää. Jos asetusta muutetaan joskus englannista suomeen, jää jäljelle tiedostoja, joiden nimessä on "Mon", "Tue" jne, kun uudella maa-asetuksella nimiin tulee "ma", "ti" jne.

Edelleen on huomioitava Unixin tiedostojen oikeudet. Niistä kertoo (paljon) enemmän kirjoitukseni Opi Linux ja tiedostojen oikeudet Akun ja Iineksen kanssa. Lyhyesti sanottuna kannattaa varmistaa umask-komennolla, että varmuuskopion lukuoikeuksia ei ole kaikilla. Kirjoita komentojonon ensimmäiseksi riviksi umask 077.

Mistä lisätietoa?

Linux-koneessa man on ystäväsi. man tar kertoo tar-komennon tuntemat valitsimet, ja kaikista tässä tekstissä mainituista komennoista saat lisätietoa samalla tavalla. Tutustu myös info-komentoon, esimerkiksi info find kertoo esimerkkien kera eri tavoista etsiä tiedostoja.

Putkitus, tulostuksen ohjaus '>'-merkillä ja muut sellaiset kuuluvat komentotulkin tehtäviin. Komentotulkki Linuxissa on yleensä bash. Siitä saat lisätietoa komennolla man bash.

Myös Ari Rantala on kirjoittanut samantapaisen jutun, joka on lukemisen arvoinen. Siinä kerrotaan muunmuassa miten ajastetun komennon saa lähettämään sähköpostilla ilmoituksen onnistuneesta ajosta.

Piditkö kirjoituksesta?

Tahtoo kommentteja! Kirjoita osoitteeseen jm58660@uta.fi ja kerro mikä oli hyvää ja mikä huonoa. Ellet ymmärtänyt jotain, niin voin muuttaa tekstiä tarpeen mukaan. Toki pelkkiä kiitoksiakin saa lähettää, sellaiset voivat saada minut jopa kirjoittamaan lisää tekstejä.


Kirjoitettu 2000-09-09, muokattu viimeksi 2003-06-12.