*Joskus käyttäjä poistaa vahingossa itseltään sudo-oikeuden ja sudo-oikeuttahan ei käyttäjä itse voi silloin palauttaa koska sudo-oikeuden palauttaminen vaatii sudo-oikeutta. Sudo-oikeus voidaan palautaa live-CD:llä automaattisesti ajamalla käyttäjän koneessa oleva skripti, mutta palautus onnistuu vain chrootissa ja silloinkin täytyy antaa käyttäjän nimi. Käsky $USER antaa nimeksi ubuntu. Mutta tuota käyttäjänimeä ei halutakaan tietää vaan sen käyttäjän nimi jonka tedostoista skriptiä ajetaan. Se selviää käskyllä: echo ${0%} | tr "/" " " | awk '{print $(NF-2)}' . Siis käyttäjälle myönnetään sudo-oikeus käskyllä: sudo chroot /mnt addgroup $(echo ${0%} | tr "/" " " | awk '{print $(NF-2)}') sudo
- echo ${0%} | tr "/" " " | awk '{print $(NF-2)}' ei koskaan toimi komentoriviltä vaan ainoastaan skriptistä.
- muuten chroot on Linuxin perusominaisuus eikä sitä tulla poistamaan. Sen käyttöä pyritään kyllä tekemään turvallisemmaksi. Chroot vaatiikin nykyään paljon enemmän kuin
  aikoinaan kuten näet skriptistä: http://forum.ubuntu-fi.org/index.php?topic=31223.msg241294#msg241294.
**
Portin tyypin saa helpoiten kun katsoo sen liittimeen: USB2 on keskeltä harmaa ja USB3 on keskeltä sininen. Mutta kyllä tiedon saa ohjelmallisestikin: työnnä muistitikku vuorollaan jokaiseen USB-liittimeen koneessasi ja anna käsky:
echo -n 'tämä portin tyyppi on: '; sudo lsusb -v | grep -A 5 $(dmesg | tail -15 | grep Manufacturer: | awk '{print $6}') | grep bcdUSB | awk '{print $2}'
- sitäpaitsi niitä on joitain kummallisiakin: esimerkiksi minun koneessani on USB2.1, USB1:täkin löytyy ...
- teoriassa muistitikku pitäisi irroittaa esimerkiksi nautiluksella ennenkuin sen vetää irti ... mutta tuurilla ne laivatkin seilaa.
**
Kun tekee käyttäjälle tarkoitettua skriptiä on syytä välttää sudo:n käyttämistä ellei se ole ihan pakko sillä ei ihmiset halua salasanaa kirjoittaa - kun ei käytä skriptiä niin eipähän tarvitse salasanaa kirjoitella ja onhan se pieni turvallisuusriskikin. Mutta toki sudo:n voi määrätä mikäli sudo on annettu jo aikaisemmin ja on edelleen voimassa. 

Sen määrittely onko sudo vielä voimassa: [[ $(sudo -n uptime 2>&1 | grep "load") ]] && echo 'sudo on vielä voimassa' || echo 'sudo ei ole voimassa'
**
15.10 muodostaa bootatessaan 16 kpl RAM-diskejä? ainakin minun koneessani. Ne ovat kooltaan 64M ja laitenimiltään /dev/ram(0..15). Saakohan käyttäjäkin käyttää niitä?

- "sudo fdisk -l" tuommoista väittää. Mutta väittäähän se myös että swap:n tyyppi on "Microsoft basic data".  
**
Kovalevyn attribuuttien selville saamiseksi on lukemattomia konsteja. Niiden yhteinen piirre tuntuu olevan se, että ne vaativat sudo:a. Esimerkiksi käsky: blkid toimii näennäisesti ilman sudo:a, mutta lähemmin tarkasteltuna osottautuu että se vaatii sittenkin kunnolla toimiakseen sudo:a. Mutta toki konsti löytyy: otetaanpa esimerkiksi osiotyypin selvittäminen:
 
udevadm info -n /dev/sda1 -q property | grep -Po '(?<=ID_FS_TYPE=).*'  

- ja samalla periaatteella saa muitakin attribuutteja
**
USB-muistitikkujen käyttöönotto on aina ollut ongelmallista: esimerkiksi noviisille on vaikeus jo se, että käyttöjärjestelmä laittaa tikun usein juuren omistukseen. Samoin tikun osiointi saattaa olla jo tehty tai sitten ei ja jos sillä on tiedosto-järjestelmä voi se olla mikätahansa. Käyttöoikeudet vaihtelee, extended atribuutteja tai piilo-osioita voi olla, sovelluksia, Windows kummittelee ...

Onko olemassa mitään sovellusta joka helpottaisi elämää? On helppo tehdä skripti joka hoitaa kyllä homman täysin automaattisesti, mutta sillä voi vahingossa tehdä myös melkoista tuhoa.
**
Output text between tags
| grep -Po '(?<=text_before).*(?=text_after)'  

eg. echo "some text<<this is supposed to be output:ted>>some other stuff" |  grep -Po '(?<=<<).*(?=>>)'  
**
Koska levylle kirjoittaminen on hidasta niin kirjoittaminen suunnataan aina RAM:miin, tarkemmin sanoen buffereihin. Buffereista tuo tieto kirjoitetaan käyttöjärjestelmän toimesti aikanaan levylle mutta saattaa kestää muutaman minuutinkin ennenkuin kaikki on varmasti kirjoitettu levylle. Mikäli kone sammutetaan aikaisemmin niin buffereissa ollut tieto katoaa. Kun tehdään ohjelmaa niin sen kiireettömiin kohtiin voi kirjoittaa käskyn: sync.
- tämän "kiireettömän" kohdan valinta on vaikeaa sillä väärään paikkaan kirjoitettuna se aiheuttaa ohjelmassa hidatelua.
- paljonko bufferoitua ja kenties levylle kirjoitettavaa on: grep ^Dirty /proc/meminfo   
**
Taas kertaalleen olen äimänkäkenä: olin siinä käsityksessä, ettei EFI salli liittää vierasta kovalevyä omaan järjestelmäänsä; ja ettei toiseen järjestelmään liitetty järjestelmä toimi kun sillä on omakin EFI. Mutta joutessani kokeilin kuitenkin ja kas kummaa: chroot toimi. Unohdin tämän toisen levyn liittimiin ja kun seuraavana aamuna ajoin päivitys-skriptin ja se päivitti myös tämän liitetyn levyn - ja "sudo update grub" lisäsi grubiin tämän liitetyllä levyllä olevan Ubuntun. Bootattaessa tähän uuteen Ubuntuun se esitti oman erikoisen työpöytänsä ja toimi muutenkin moitteetta.                     
**
Ohjelmat muodostuvat joskus monesta osasta joista joku/jotkut keräävät tietoa ja kirjoittavat sen jonnekin ja joku/jotkut lukevat sitä ja tulostavat sen sitten näytölle. Käsiohjauksella työ on yksinkertainen: ensin ajetaan ohjelma joka kerää tiedon ja kirjoittaa sen jonnekin ja kun se on lopettanut niin ajetaan ohjelma joka lukee niitä tietoja ja tulostaa ne näytölle. Mutta entäpä jos tuo tiedonkeruu voi alkaa joko hetikohta tai kuukauden kuluttua tai peräti pätkittäin? Tämä ongelma ratkeaa nimetyn-putken avulla. Toiminnan kuvaus yksinkertaisimmillaam:

Avaa ensimmäinen pääte (esimerkiksi painamalla ctrl-ALT-t) ja:
anna käsky: mkfifo NimettyPutki   
anna käsky: echo hilipatarallaa > NimettyPutki   # enterin painamisen jälkeen ei tapahdu enää mitään, edes uutta kehotetta ei tule

avaa toinen pääte (esimerkiksi painamalla ctrl-ALT-t) ja anna käsky: cat NimettyPutki
se tulostaa: hilipatarallaa
palaa ensimmäiseen päätteseen ja huomaat että se on tulostanut jälleen kehotteen.

- muodostuvaan NimettyPutki-nimiseen tiedostoon voi soveltaa kaikkia niitä toimia joita tiedostoon yleensäkin. 
**
NimettyäPutkea voidaan käyttää esimerkiksi kun kaksi skriptiä toimivat eripitkään, mutta silti haluna olisi että ne toimisivat yhtämonta kertaa. Tämän aikaansaamiseksi nopeampi laitetaan odottaman hitaamman valmistumista. Kumpihyvänsä saa olla se hitaampi, tulostusjärjestys kylläkin muuttuu.  
- tottakai BASH:issa on toisia parempiakin keinoja mutta onhan tämä yksi menetelmä.

Tee skripti nimeltä: skripti1
#!/bin/bash
rm -f NimettyPutki && mkfifo NimettyPutki
while true; do
  Alkuhetki=$(date +%s.%N)
  sleep 1 # sleep:in tilalle voi laittaa minkähyvänsä toiminnon ja sen kuluttama aika tulostuu
  Loppuhetki=$(date +%s.%N)
  echo -e 'skripti1:n suoritusaika: '$(echo $Loppuhetki-$Alkuhetki | bc -l)'\n' > NimettyPutki # samalla skripti1 lukitsee itsensä
done

Tee toinen skripti nimeltä: skripti2 
#!/bin/bash
while true; do
  Alkuhetki=$(date +%s.%N)
  sleep 10 # sleep:in tilalle voi laittaa minkähyvänsä toiminnon ja sen kuluttama aika tulostuu
  Loppuhetki=$(date +%s.%N) 
  echo 'skripti2:n suoritusaika: '$(echo $Loppuhetki-$Alkuhetki | bc -l)
  cat NimettyPutki # tämä vapauttaa skripti1:n 
done


Toiminta:
Avaa pääte (paina ctrl-ALT-t) ja käske:         . skripti1
Avaa toinen pääte (paina ctrl-ALT-t) ja käske:  . skripti2
 
Alkaa tulostua 10sekunnin välein jotain seuraavankaltaista:
skripti2:n suoritusaika: 10.005455598
skripti1:n suoritusaika: 1.005531242

- putkeen voi kirjoittaa kukatahansa ja vaikka monesta paikasta. Samoin putkesta voi lukea kukatahansa ja vaikka monesta paikasta.
- tässä skriptit pysäytetään painamalla ctrl-c. Kumpikin on syytä pysäyttää.
**
Iso kansio vie talletettaessa kovalevytilaa erilaisilta levyiltä erilaisia määriä. Onko ohjelmia jotka osaavat ennakoida tämän?

- siis tavallaan haluaisin seuraavankaltaisen käskyn: talletuskoko kansio_polkuineen levy
- siis käytännössä kirjoitettaisiin: talletuskoko /home/käyttäjänimi sda 

- voisihan itsekin väsätä tällaisen skriptin. Mutta siinä olisi iso työ, ja salahautoja olisi vilisemällä. Niinkuin esimerkiksi btrfs-tiedostojärjestelmä. 
**
Tutkin taas kerran kuinka tekstistä saa erotettua tagien välisen tekstin. Tapoja on lukemattomia ja todella erikoisia konsteja on vaikka minkälaisia. Pari yksinkertaista:
- tagit saavat olla eri riveilläkin

grep -Pzo '(?s)begin.*end'                         # (?s) on ohje regex:älle siitä että . vastaa myös rivinsiirtoa. i->merkkikoko ei vaikuta. kytkimet -Pz oleellisia.
grep -Pzo '(?s)(?<=begin).*(?=.*end)               # tagien paikoilla on tyhjää
grep -o tämä.*paremmin                             # tagit kirjoitetaan myös
sed -n '/begin/,/end+/ { p }'                      # kirjoita lohkojen väliin tyhjä rivi. Siis esimerkiksi: cat /boot/grub/grub.cfg | sed -n '/BEGIN/,/END+/ { p }'
awk '/BEGIN|begin|<</,/END|end|>>/ {print $0}'     # | merkki on TAI   
- myös regex:t sopii: lspci -v | awk '/VGA/,/^$/'  # lohkon alku on teksti: VGA ja loppu on tyhjä rivi
- tiedostoissa on joskus epäkelpoja merkkejä. Tällöin esimerkiksi: cat /boot/grub/grub.cfg | tr -dc [[:graph:]]'\n' | grep -Pzoi '(?s)begin.*end'
**
Päivitän kokeiluversion aina päätteessä sillä olen kehittänyt uskomuksen että kun päivitys-teksteissä alkaa esiintyä huomautuksia on aika asentaa kokeiluversio uudestaan. Niin myös tänään.        
**
function catt() { for i in "$@"; do if [ -d "$i" ]; then ls "$i" else cat "$i"; fi; done ;}; catt *
**
On jatkuva yllätyksen aihe kuinka nopea BASH itseasiassa on - taikka eihän BASH ole nopea mutta se saa asiat tehtyä nopeasti kun oikein käsketään. Taas kertaalleen sain kokea oikean käskytavan löytämisen vaikeuden kun yritin tehdä skriptiä joka etsii joukon kaikki kombinaatiot. Siinä muuten kului aikaa ja tupakkia. Lopulta skripti supistui muotoon: 
function kombinaatio (){ eval echo $(printf "{%s,}" "$@"); }    # kutsu: kombinaatio a b c d 
Skripti toimiikin nopeasti mutta mikäli nopeampaa tarvitaan niin kyllä se BASH:ilta onnistuu vaikka minulta ei.
**
Samoin kertoman laskussa skripti kuluttaa tuhottomasti aikaa ja resursseja mikäli skriptin tekee väärin. Mutta oikentehtynä skripti on nopea, sen arvoalue on rajoittamaton ja sen kirjoitusasu on yksinkertainen. Koetapa laskea muillakeinoin "100000 kertoma" vaikka eihän siinä juuri mieltä ole. Matikassa vaan ohjelmat eivät saa rajoittaa. Esimerkki:
function kertoma () { [[ $1 -eq 0 ]] && kertoma=1 || kertoma=$(seq -s* $1 | bc | tr -d '\\\n' ) ;}; time kertoma 555; echo $kertoma 
- kertoma-funktion nimeksi kelpaa kyllä ! ja huutomerkki toimisi vaikka se olisi perässäkin. Mutta silloin skripti olisi paljon isokokoisempi. 
**
Kovalevytilan mittaamisen jälkinäytös

Kiitos nm:n sain kovalevytilan mittaamiseen järkeä. Mutta sillä on jälkinäytös: 

Yhtenä päivanä surffasin muutaman tunnin boottaamisen jälkeen ja senjälkeen mittasin kovalevytilan ja laitoin tuloksen muistiin. Sitten boottasin uudestaan ja mittasin kovalevytilan heti ja vertasin tulosta muistiin laitettuun. Tilaa oli vapautunut noin .2GB .

Netistä luin että tämä on Linuxia vaivaava ominaisuus: sovellukset tuhoavat tiedostojaan siten että tiedostojärjestelmän kannalta tiedostojen kovalevytila jää käyttöön ja vapautuu suurimmaksi osaksi vasta kun sovellukset lopetetaan - sovellukset lopetetaan myös kun kone sammutetaan oikein mutta joskus voi käydä niinkin että roskat eivät häviä edes bootatessa - vaikka sovellukset ovat teoriassa lopetetut niin ne silti elävät zombeina ja varaavat kovalevytilan uudestaan. Tällöin käske: killall häiriköivä_sovellus. Roskanmuodostuminen voi olla nopeaakin ja sitä voi olla paljon. 

listauksen varausten lukumäärästä ja niiden vaatimasta kovalevytilasta saa käskyllä: 
[code]
# sudo lsof -nP 2> /dev/null | awk '/deleted/ { sum+=$8 ; lkm+=1} END { print "tyhjien varauksien lkm:"lkm" ja niiden kovalevyltä yhteensä varaama tila sanoja(?):"sum }'
lsof +L1 | awk '{ sum+=$7 ; lkm+=1} END { print "tyhjien varauksien lkm:"lkm" ja niiden kovalevyltä yhteensä varaama tila sanoja(?):"sum }'
[/code]
- tilaa vapautuu vähäsen itsekseenkin kun lopetat tekemisesi, mutta vain muutamia minuutteja.
- Linux raamatun mukaan käsky: lsof +L1 listaa deletoidut tiedostot. Kuitenkaan niiden määrä eikä niiden varaama koko ole sinnepäinkään. Mutta niiden nimille voi määrätä kilall

Varatun kovalevytilan sanoina saa tietää käskyllä:
[code]  
du -sB1 2> /dev/null
[/code]
- kovalevytilaa vapautuu bootatessa mielestäni hieman suurempi määrä kuin varattujen tiedostojen poistuminen edellyttää.
**
LANG=fi_FI.UTF-8
**
Sekä bufferit että cachet ovat RAM-muistissa. Niiden tarkoituksena on toimia välimiehenä ulkoisten laitteiden ja prosessorin välillä. Esimerkiksi kovalevy on ulkointn laite. 
 
Kun ulkoiselle laitteelle kirjoitetaan niin prosessori kirjoittaa ensin RAM-bufferiin ja määrää toiset kirjoittamaan bufferin sitten ulkoiselle laitteelle.

Kun ulkoiselle laitteeltä luetaan niin prosessori määrää muut suorittamaan lukemisen, viemään luetun cacheihin ja ilmoittamaan sitten kun luettava on cacheissa. Tämän jälkeen prosessori siirtyy muihin tehtäviin jos sellaisia on.

Nämä toimet tapahtuvat lohko kerrallaan - esimerkiksi sektori tai segmentti. Suoraa vastaavuutta tiedostolla ja cache/buffereilla ei siten ole vaan tiedostosta saattaaa olla niistä osia  
**
Aina oppii. Seuraavat käskyt kertovat mistä on kyse:
echo "<<tulostetaan>>ei saa tulostua<<tulostetaan>>" |  grep -Po '(?<=<<).*(?=>>)'      # mikäli tag-ryhmiä on samalla rivillä useampia niin tuloste on väärä
ja:
echo "<<tulostetaan>>ei saa tulostua<<tulostetaan>>" |  grep -Po '(?U)(?<=<<).*(?=>>)'  # tämä taas tulostaa aina oikein. Ungreedy voi kylläkin myös sotkea
tätä voi jalostaa edelleen:
cat tiedosto |  grep -Po '(?Us)(?<=<<).*(?=>>)'                                         # tai sitten ei mikäli tag:ien välinen teksti on monella rivillä. Tämä on silloinkin oikein.
**
Aivan toisenlaisella lähestymistavalla haetaan ratkaisua samantapaiseen asiaan - tässä kylläkin on tarkoituksena tulostaa tiedoston ne lohkot joissa lukee jollakin rivillä määrättävä sana missäkohtaa lohkoa tahansa:
[code]
awk -v RS='' '/sana/ {print $0"\n"}' tiedosto
[/code]
- lohko elikä kappale on rivijoukko jota kummaltakin puolelta rajoittaa tyhjärivi.
- kaikki ne kappaleet tulostetaan joissa on tuo sana. Jos jossakin kappaleessa ei ole tuota sanaa ei sitä myöskään tulosteta.
- tässä tulostuvien lohkojen väliin tulostuu tyhjärivi
- on aivan sama mitä sanaa etsitään, kunhan se on lohkoissa joita halutaan eikä ole lohkoissa joita ei haluta.
- sanaksi kelpaa regex - voihan siitä käyttää nimitystä tag sillä siitä on kysymys
- mikäli halutaan että tulostetaan sittenkin kahden tagin välinen teksti niin käsky muuttuu seuraavankaltaiseksi:
[code]
sed "s/tag1/\n\ntag1/g;s/tag2/\n\ntag2/g" tiedosto | awk -v RS='' '/tag1/ {print $0"\n"}' | sed -e 's/tag1//g'
tai:
cat /boot/grub/grub.cfg | awk '/BEGIN|begin|<</,/END|end|>>/ {print $0}/END|end/>>/{print "\n"}' # lohkojen väliin tulee tyhjärivi
[/code]
- tag:it saavat olla mielivaltaisia merkkejä, vaikka << ja >> 
- tiedoston teksti saa olla yhtenä pötkönä ilman yhtäkään rivinsiirtoa, mutta saa siinä rivinsiirtojakin olla.
- tällaista käskyhirviötä on pakko käyttää mikäli koneen regex ei ole oikeanlainen.

**
Koko BASH on siis pelkkää kikkaa ja on täysin mahdotonta muistaa noista kikoista pientäkään osaa, puhumattakaan siitä että uusia keksitään kokoajan. Kirjastot ovat siis ehdoton välttämättömyys ja niitä täytyy päivittää usein. Mutta asia ei ole sillä selvä että käyttäjälleIP="17.255.8.44"; for n in {0..255}; do echo $IP | grep -w $n; done | [[ $(wc -l) = 4 ]] && echo IP is ok || echo IP is not ok annetaan kirjastot vaan täytyy olla myös keinot etsiä kirjastosta koska kirjastofunktioita olisi niin paljon ettei kukaan voi muistaa edes sitä minkäkaltaisia funktioita kirjastossa on.
- ohjelmoitaessahan ei saa käyttää kikkoja. Mutta BASH ei olekaan ohjelmointikieli vaan kuvauskieli eli ohjelmageneraattori.
**
Tämä liittyy aika-mittauksien keskiarvonmuodostukseen; tulokset ovat joskus aivan vääriä.

Anna käsky: time echo jotakin
ja katso user-aika. Anna sama käsky uudestaan. User-aika on muuttunut nollaksi. On muuten ihan sama mitä " time echo:atkin" tämänjälkeen niin user-aika on nolla.

Mutta käsky: time ls ~
antaa aina  vaihtelevan ajan.
**
Osa Linuxin käskyistä on niin nopeita että Time-käsky väittää niiden nopeudeksi nolla ja muilla menetelmillä saadut tulokset heittelevät mahdottomasti. Arvoista saa vakaita ajoittamalla käskyt monta kertaa ja ottamalla tuloksesta keskiarvon.
Tällätavoin menetetään tulosten absoluuttinen arvo, sillä silloinhan todennäköiseti mitataan cache:ja, buffer:eita tai onhan noita muitakin. Mutta yhtä asiaa ei menetetä: samantapaisten käskyjen
suoritusaikojen suhteellista eroa: esimerkiksi kun mitataan suoritusajat käskyille <echo a>" ja <printf "%s\n"> niin voi olla varma että niiden suhteellinen ero on oikea. 
Koska tämä ratkaisee sen, kuinka skripti kannattaa kasata voi ajat esittää mIP="17.255.8.44"; for n in {0..255}; do echo $IP | grep -w $n; done | [[ $(wc -l) = 4 ]] && echo IP is ok || echo IP is not okyös absoluuttisina joten seuraava pitää paikkansa:

Ei BASH kaikessa hidastele. Esimerkiksi nolla-operaatio jonka merkkinä on kaksoispiste (eli : ) kestää myös lähes nollan. Funktiokutsu on sekin nopea, luokkaa 1 mikrosekunti.
Tavallinen echo:kin on nopea ja mikäli sillä on parametrina vain yksi kirjain elikä esimerkiksi: echo a   
niin sen nopeus on noin 3.5 mikrosekuntia. Printf "%s\n"
on hitaampi kestäen 4.9 mikrosekuntia.
yksinkertainen vertailu elikä esimerkiksi: [[ $a = 1 ]] && tee_jotakin
kestää noin 5 mikrosekuntia. Nopea on myös käsky:
echo ${muuttujanimi//jotakin/joksikin_muuksi}
joka kestää luokkaa 7mikrosekuntia joten onhan tuo pikkusen nopeampi kuin sed joka vie putkituksineen noin 3ms.
- mutta kun ei käsitelläkään tekstijonoja vaan tiedostoja niin BASH käsky on: readarray a < tiedosto;echo "${a[*]//mikä/miksi}"  ja vastava sed-käsky: sed 's/mikä/miksi/g' tiedosto
ja jostain syystä BASH-käsky on joillain tiedostoilla kaksikertaa nopeampi ja joillain toisilla tiedostoilla kaksikertaa hitaampi kuin sed-käsky. 

uuden prosessin muodostaminen kestää vajaan millisekunnin. Siis käskyjä ei pidä ryhmittää näin: ( käskyryhmä ) sillä tapa siis lisää millisekunnin suoritusaikaan ja vaikka se perii muuttujien arvot muodostajaltaan niin se ei palauta niitä - ja vain harvoin tästä on etua. Käskyjen ryhmittäminen kannattaakin yleensä tehdä näin: { käskyryhmä; } sillä siten ryhmittäminen vie ylimääräistä noin 2 mikrosekuntia ja muuttujat ovat samoja.
**
Esimerkiksi kysypä kuinka tulostetaan tiedoston viimeinen rivi. Vastauksena tarjotaan ilmanmuuta: cat tiedosto | tail -1 . Kuitenkin helpointa olisi käskeä: tail -1 tiedosto . Sen suoritusaikakin on pikkuisen nopeampi.
- mutta toisaalta ongelmattomin ja nopein käsky tiedoston viimeisen rivin tulostamiseen on: awk '{ if (NF > 0) n = $0 }END{print n}' tiedosto
**
Halutessasi salata tiedoston voit käyttää käskyjä:
openssl enc -aes-192-cbc -in tiedosto -out tiedostosalattuna     # kun haluat salata tiedoston
openssl enc -d -aes-192-cbc -in tiedostosalattuna -out tiedosto  # kun haluat lukea tiedoston 
- kumpikin kysyy salausavainta. Yksinkerainenkin salausavain riittää tekemään tiedostot lukukelvottomiksi muille kuin super-krakkereille 
** tai:
# Encrypt file
$ gpg --symmetric --cipher-algo AES192 --output encrypted.enc plain.txt
# Decrypt file
$ gpg --decrypt --output plain.txt encrypted.enc

# Encrypt stdin to file
$ tar -czvf - tiedosto | gpg --symmetric --cipher-algo AES192 --output tiedostosalattuna
# Decrypt file to stdout
$ gpg --decrypt archive.tar.gz.enc | tar -xzvf -
**
Koneessani on aina vähintään kaksi Ubuntua: viimeinen virallinen- ja kokeiluversio. Kun koneen Ubuntuista joku päivittää itsensä boottaamattomaksi niin tämä skripti ajetaan kun on bootattu samassa koneessa joltain muulta: kovalevyltä tai live-tikulta/live-CD:ltä. Päivittäminen onnistuu mikäli boottausvälineen verkkoyhteydet toimivat. Live-tikun/Live-CD:n verkkoasetukset tehdään samallatavoin kun kovalevylläkin. Päivitys-skripti on paras sijoittaa kovalevyn koti-kansioon ja ajaa sieltä nautiluksella. Päivitys-skripti päivittää kaiken minkä löytää - jos olet unohtanut USB:lle jonkun Ubuntu-version niin sekin päivitetään.

Skriptiin on liitetty paljon muutakin mikä poistaa turhaa sälää, poistaa päivityksen esteitä ja pitää Ubuntut hyvässä kunnossa. Btrfs:llä tämä ei toimi ilman virittämistä mutta muut tiedostojärjestelmät kyllä toimii. Myöskään EFI ei ole este. Ja on tässä sekin kiva piirre että kaikki päivittyy kerralla.

- kyllä tämä Mintilläkin toimii ja varmaan monella muullakin. Mutta perus-Ubuntulle ja ext4:lle tämä on tarkoitettu.

- ei tämäkään poista backup:pien tarvetta.

Päivitysskriptin koodi:

 En yleensä tee mitään suurempaa  kokeiluversiolla mutta aina silloin-tällöin tulee tehtyä eikä koskaan ole sattunut mitään kummallista. Kokeiluversion merkityksellisin huono puoli tuntuu olevan se että se joskus päivittää itsensä boottaamattomaksi niinkuin kävi eilenkin. Mutta ongelma korjaantuu boottaamalla viralliseen versioon ja ajamalla koti-kansiossa oleva päivitys-skripti; senjälkeen on aina bootannut myös kokeiluversioon - näin on ollut jo seitsemän vuotta. Chroot:iin meneminen täytyi aikoinaan muuttaa mutta mitään muuta ei. 

- joskus virallinenkin versio päivittää itsensä boottauskelvottomaksi - ja saattaahan sattua että kokeiluversiokin on päivittänyt itsensä boottauskevottomaksi samaan aikaan. Silloin täytyy bootata live-cd:llä ja ajaa tuo sama kovalevyn koti-tiedostossa oleva päivitys-skripti live-cd:n nautiluksella. 
**
# 14.10.2015 petteriIII.
# Tämä päivitys-skripti paivittää kovalevyltä sen kaikki Ubuntut (ja monet muutkin Linuxit).
# Toimii vaikka päivitettävillä levyillä olisi kullakin oma EFI. Ja kaikki koneen tuntemat päivitetään niin omalta kovalevyltä, USB:llä liitetyiltä, SATA:lla liitetyiltä kuin eSATA:lla liitetyiltä ...
# verkon kautta ei varmaankaan päivitä ennenkuin koodiin tekee muutoksia. Tai ehkäpä Samba riittää.
#
# Mikäli kovalevyltä ei voi bootata niin täytyy bootata esimerkiksi live-tikulta. Mikäli on bootattu live-tikulla ei salasanaa kysytä. Päivitys-skripti voidaan ajaa esimerkiksi
# kovalevyltä käyttäen live-tikun nautilusta.
#
# skripti voi sijaita missähyvänsä paikassa johon pääsee nautiluksella - siis vaikka boottaamattomalla konella sillä kyllä nautiluksella sinne pääsee.
# skriptinajamisen mahdollistaminen nautiluksessa: avaa nautilus - ruudun yläpalkista: muokkaa - asetukset - Toiminta - täppä kohtaan: kysy joka kerta
# Btrfs-tiedostomuoto vaatii päivitys-skriptiin muutoksia.
# Kun on bootattu live-USB-muistitikulta tarkistetaan kovalevyn kaikki osiot. Kun on bootattu kovalevyllle ei boottaus- eikä koti-osiota tarkisteta.
# Ennen päivitystä yritetään poistaa kaikki päivityksen esteet ja turhista roskista pyritään eroon.
# Jos koneessa on lukemattomia imageja saattaa päivittäminen kestää pitkäänkin, mutta muuten päivitys toimii yhtä nopeasti kuin tavallinenkin päivitys.

**

Koneessani on aina vähintään kaksi Ubuntua: viimeinen virallinen- ja kokeiluversio. Kun koneen Ubuntuista joku päivittää itsensä boottaamattomaksi niin tämä skripti ajetaan kun on bootattu samassa koneessa joltain muulta: kovalevyltä tai live-tikulta/live-CD:ltä. Päivittäminen onnistuu mikäli boottausvälineen verkkoyhteydet toimivat. Live-tikun/Live-CD:n verkkoasetukset tehdään samallatavoin kun kovalevylläkin. Päivitys-skripti on paras sijoittaa kovalevyn koti-kansioon ja ajaa sieltä nautiluksella. Päivitys-skripti päivittää kaiken minkä löytää - jos olet unohtanut USB:lle jonkun Ubuntu-version niin sekin päivitetään.

Skriptiin on liitetty paljon muutakin mikä poistaa turhaa sälää ja pitää Ubuntut hyvässä kunnossa. Btrfs:llä tämä ei toimi ilman virittämistä mutta muut tiedostojärjestelmät kyllä toimii. Ja on tässä sekin kiva piirre että kaikki päivittyy kerralla.

- kyllä tämä Mintilläkin toimii ja varmaan monella muullakin. Mutta perus-Ubuntulle ja ext4:lle tämä on tarkoitettu.

- ei tämäkään poista backup:pien tarvetta.

Päivitysskriptin koodi:

Koodia: [Valitse]

#!/bin/bash
# 14.10.2015 petteriIII.
# Tämä päivitys-skripti paivittää kovalevyltä sen kaikki Ubuntut (ja monet muutkin Linuxit).
# Toimii vaikka päivitettävillä levyillä olisi kullakin oma EFI. Ja kaikki koneen tuntemat päivitetään niin omalta kovalevyltä, USB:llä liitetyiltä, SATA:lla liitetyiltä kuin eSATA:lla liitetyiltä ...
# verkon kautta ei varmaankaan päivitä ennenkuin koodiin tekee muutoksia. Tai ehkäpä Samba riittää.
#
# Mikäli kovalevyltä ei voi bootata niin täytyy bootata esimerkiksi live-tikulta. Mikäli on bootattu live-tikulla ei salasanaa kysytä. Päivitys-skripti voidaan ajaa esimerkiksi
# kovalevyltä käyttäen live-tikun nautilusta.
#
# skripti voi sijaita missähyvänsä paikassa johon pääsee nautiluksella - siis vaikka boottaamattomalla konella sillä kyllä nautiluksella sinne pääsee.
# skriptinajamisen mahdollistaminen nautiluksessa: avaa nautilus - ruudun yläpalkista: muokkaa - asetukset - Toiminta - täppä kohtaan: kysy joka kerta
# Btrfs-tiedostomuoto vaatii päivitys-skriptiin muutoksia.
# Kun on bootattu live-USB-muistitikulta tarkistetaan kovalevyn kaikki osiot. Kun on bootattu kovalevyllle ei boottaus- eikä koti-osiota tarkisteta.
# Ennen päivitystä yritetään poistaa kaikki päivityksen esteet ja turhista roskista pyritään eroon.
# Jos koneessa on lukemattomia imageja saattaa päivittäminen kestää pitkäänkin, mutta muuten päivitys toimii yhtä nopeasti kuin tavallinenkin päivitys.

function KirjoitaOhje { echo '- ennen päivittämistä kannaattaa sulkea muut ohjelmat.
- aluksi kysytään salasanaa ettei sitä kysyttäisi sitten toiminnan aikana keskenkaiken. Salasana on kovalevyllä toimittaessa oma ja live-tikulla sitä ei kysytä - mutta jos kysytään niin se on: ubuntu
  salasanasi ja muistitikulla toimittaessa se on ubuntu jos sitä edes kysytään.
- toimiva internet-yhteys on välttämätön; live-versioiden verkkoyhteys asennetaan aivan samoin kuin normaalistikin - muistitikun asetukset säilyvät mutta cd:n ei.
- kovalevyosiot tarkistetaan ja yritetään korjata lukuunottamatta sitä osiota jolla on bootattu. Windows on kylläkin kantona kaskessa.
- roskikset tyhjennetään, vain viimeinen image jätetään ja päivityksen esteitä poistetaan.'; }

function tarkistaKovalevyjenKaikkiOsiot () {
read -t 5 -n 1 -p 'jos haluat tarkistaa kovalevyn perusteellisesti paina jotain kirjainta; silloin tarkistus kestää jonkinverran kauemmin mutta tarkistaa paremmin.' apu
echo
for osio in $(sudo blkid | grep -v swap | awk '{print $1}' | sed 's/\://g'); do
  [[ $(echo $osio | grep loop) ]] && continue
  sudo fsck -MVCaf $osio ||   sudo fsck -MVCac $osio
  echo ""
done
}
IP="17.255.8.44"; for n in {0..255}; do echo $IP | grep -w $n; done | [[ $(wc -l) = 4 ]] && echo IP is ok || echo IP is not ok
function unmountmnt { # if grep -qs '/mnt/foo' /proc/mounts; then
cd / # umount ei onnistu, jos joku umountattavan kansio on valittuna
sudo echo ""
for mountattu in $(sudo mount | grep /mnt | awk '{print $3}')
do
  if grep -qs $mountattu /proc/mounts; then sudo umount -l $mountattu; fi
done 
echo '/mnt:n mountit on poistettu'
}

function Levy { echo -n $(ls -l /dev/disk/by-id | grep -m 1 '/'${Chrootosio##*/} | awk '{print $9}' | sed "s/-part*//g");}

function paivitaKaikkiOsiot () { # itseensä chroottaus onnistuu ihan kivasti joten tällätavoin voi ihan hyvin päivittää itsensä
unmountmnt
for Chrootosio in $(sudo blkid | grep -v swap | grep -v vfat | awk '{print $1}' | sed 's/\://g'); do
  osiontyyppi=$(sudo blkid -o value -s TYPE $Chrootosio)
  sudo mount -t $osiontyyppi $Chrootosio /mnt
  [[ -d /mnt/boot/grub ]] && [[ $(cat /mnt/boot/grub/grub.cfg | grep menuentry.*Ubuntu ) ]] &&  {
  sudo mount -t sysfs none /mnt/sys && sudo mount -t proc none /mnt/proc && sudo mount --bind /dev/ /mnt/dev &&  sudo mount --bind /dev/pts /mnt/dev/pts && sudo mount -o bind /etc/resolv.conf /mnt/etc/resolv.conf && sudo mount -o bind /dev/shm /mnt/dev/shm
  echo; echo -n '********** päivitetään: '$Chrootosio '   levyllä: '; Levy; echo '     tiedostomuoto: '$osiontyyppi; echo		
  [[ -d /mnt/home/$(env | grep USER)/.local/share/Trash ]] && sudo rm -rf /mnt/home/$(env | grep USER)/.local/share/Trash # poistaa roskikset kaikilta osioilta joiden käyttäjä on sama kuin se jonka tililtä päivitä-skriptiä ajetaan eikä eriliskodin roskisia tyhjennetä koskaan

  # Kohdekoneen muistin vapauttaminen ei helpota tätä ohjelmaa. Kohdekoneen siistimisen syy onkin se, että kohdekone pärjäisi tulevaisuudessa itsekseen.
  sudo chroot /mnt tune2fs -m 1 $Chrootosio # rajoittaa pääkäyttäjälle varattua kovalevytilaa yhteen prosenttiin.

  # poistetaan kaikki muut imaget paitsi se jolla toimtaan. Siis mikäli on tullut uusi image jos se toimii niin sen uusi päivitys poistaa senkin.
  for n in $(ls /mnt/boot | grep config | grep -v $(ls /mnt/boot | grep config | sort | tail -1) | sed 's/config-//g'); do
    sudo chroot /mnt apt-get --yes --force-yes purge 'linux-image-'$n
    sudo chroot /mnt apt-get --yes --force-yes purge 'linux-image-extra-'$n # turha lause, mutta muistutuksena siitä mitä tapahtuu.
    sudo chroot /mnt apt-get --yes --force-yes purge 'linux-headers-'$n
  done # Mikäli et halua poistaa imageja kommentoi nämä 5 riviä

  # seuraavia kommentointeja poistetaan kun haetaan vikaa jos päivitys-skripti toimisi joskus virheellisesti; ei toistaiseksi ole tarvittu 
  #sudo fuser -cuk /var/lib/dpkg/lock; sudo rm -f /var/lib/dpkg/lock   
  #sudo fuser -cuk /var/cache/apt/archives/lock; sudo rm -f /var/cache/apt/archives/lock
  sudo chroot /mnt rm -f /var/cache/apt/archives/lock /var/lib/aptitude/lock /var/lib/dpkg/lock /var/lib/apt/lists/lock
  #sudo chroot /mnt rm /var/lib/apt/lists/*$ sudo rm /var/lib/dpkg/lock$ sudo rm /var/cache/apt/archives/lock

  sudo chroot /mnt apt-get check # korjaa pakettivaraston riippuvuudet
  sudo chroot /mnt dpkg --force-confnew --configure -a
  sudo chroot /mnt apt-get --yes --force-yes --fix-broken install
  sudo chroot /mnt apt-get --yes --force-yes autoclean
  #sudo chroot /mnt apt-get --yes --force-yes clean # poistaa osittaiset_ja_vahingoittuneet paketit ja tekee homman varmemmaksi, mutta hidastaa toiminnan mateluksi.
  sudo chroot /mnt apt-get --yes --force-yes autoremove
  # jos jossain vaiheessa kun vahingoittueen paketin nimi selviää saa sen poistettua: sudo dpkg --remove -force --force-remove-reinstreq paketin_nimi
  sudo chroot /mnt apt-get update
  [[ $(env | grep USER.*=ubuntu) ]] && sudo chroot /mnt apt-get -y upgrade || sudo chroot /mnt apt-get -y dist-upgrade
  sudo update-grub $Chrootosio && echo -n 'grub.cfg sijoitettiin levylle: '; Levy
} # vastaava avaava sulkumerkki on rivillä 38
unmountmnt
done
}

# Pääohjelma
KirjoitaOhje
echo ''; sudo echo
hommaalkoi="$(date +%s)"
tarkistaKovalevyjenKaikkiOsiot # sitä osiota jolta on bootattu ei tarkisteta.
paivitaKaikkiOsiotIP="17.255.8.44"; for n in {0..255}; do echo $IP | grep -w $n; done | [[ $(wc -l) = 4 ]] && echo IP is ok || echo IP is not ok
echo -e 'päivitetty: '$(date +"%d-%m-%y %k:%M")'\t ja päivittäminen kesti: '$(date -d@$(echo $(date +%s)-$hommaalkoi-7200 | bc) | awk '{print $3}')

« Viimeksi muokattu: tänään kello 10:21 kirjoittanut petteriIII »
Kirjattu
**
apu=e; [[ $(sudo lsof 2>/dev/null | grep synaptic) ]] && { read -p "Synaptic tuntuu olevan toiminnassa. Lopetanko sen ?" apu; [[ $apu = e ]] && { echo "sitten päivittäminen täytyy lopettaa"; sleep 2; exit ; } || { echo "synaptic on lopetettu"; sudo killall synaptic ; };}
**
Esitetäänpä esimerkki sieltä mielettömyyksien osastolta: skripti joka laskee tiedostossa olevien määrättävän merkin lukumäärän: siihenhän on ihan kiva käsky: grep -o merkki tiedosto | wc -w . Kuitenkin käsky:  tr -dc merkki < tiedosto | wc -c on kymmenen kertaa nopeampi.
- tuota grep-versiota on kylläkin pakko käyttää kun etsitään sanoja. Tai ...
- eihän kumpikaan nopea ole - mutta otapa huomioon että kyse on ohjelmasta jota ei ole juurikaan kehitetty 50 vuoteen.
- jokainen ongelma tuntuu olevan hieman vastaavanlainen: valitettavasti asia on muuten niin etteivät ohjelmoijat voi niitä parhaita käskyjä löytääkään vaan siihen tarvitaan maitokuskin apumiestä.
**
cachet siis ovat yksi syy miksi käskyjen tarkka ajoittaminen vaatii pitkiä odotusaikoja. Linuksissa on käsky joka nollaa sellaiset cachet joissa ei ole mitään sellaista jota ei kovalevyltä löytäisi. Mutta sen laittaminen käskyjen ajoittamiseen ei ole hyvä idea sillä tuo käsky kestää milloin mitäkin, yleensä kuitenkin millisekunteja. Seuraava käsky käytääkin menetelmää jossa tuon cachejen tyhjennykseen menevä aika lasketaan jokakierroksella ja vähennetään siitä ajasta joka pitäisi odottaa. Käsky ja sen kutsu ovat seuraavat:
function torku () { alku=$(date +%S%N); sudo /sbin/sysctl vm.drop_caches; loppu=$(date +%S%N); sleep $(echo "($1-($loppu-$alku))/1000000000" | bc -l) ; }; sudo echo; time torku 100000000 

jossa torkkuaika annetaan nanosekunneissa. Eihän torkku-aika ole edes yhtä tarkka kuin sleep-käskyssä mutta siitä ei ole kysymyskään sillä käskyllä haetaan vakautta.
- huomenissa alan kokeilla tyhjentääkö tämä oikeat cachet.
**
Echo:kin on nopea kuten itse voit todeta käskyllä: merkkijono=$(cat /dev/urandom | base64 | head -c 6000); time echo $merkkijono
joka muodostaa ensin 6000-merkkisen sanan ja tulostaa sen sitten ajoitettuna: echo kestää koneen nopeudesta riippuen 0-2ms. Siitä tulee siis alle 0.15 mikrosekuntia kirjainta kohti- echo-käskyn kutsu kylläkin kestää kauemmin.
- printf on hieman hitaampi.
**
Kun kymmenen vuotta sitten aloin harrastaa Ubuntua tutustuin myös tesdiskiiIP="17.255.8.44"; for n in {0..255}; do echo $IP | grep -w $n; done | [[ $(wc -l) = 4 ]] && echo IP is ok || echo IP is not okn ja se oli minusta ihan käsittämätön ja sen ohjeet sellaiset ettei ne pelottivat minua. Koetin taas tänään käyttää testdisk:iä ja sain siihen paljonkin järkeä - todennäköisesti koska tajusin välttää lukemasta ohjeita. Ohjeet ovat ihan varmasti täysin oikeat eikä syy olekaan siinä vaan syy on siinä kuka ohjeet on tehnyt ja kenelle ne on tarkoitettu: ohjeet on tehnyt virtuoosi ja ne ovat tarkoitetut toisille virtuooseille.
!
function Xref () { ##
function TulostaMuuttuja () {
[[ $(eval echo \$$1) ]] && echo -n $1' on numero- tai tekstimuuttuja arvoltaan: ' && eval echo \$$1 || echo $1" on määrittelemätön"
}

function TulostaMatriisi () {
echo $1' on matriisi.' 
[[ $(eval echo \${$1[*]}) ]] && { 
echo -n 'arvot    : '; eval echo \${$1[*]}   # arvojen väliin tulostuu välilyönti
echo -n 'osoitteet: '; eval echo \${!$1[*]}  # osoitteiden väliin tulostuu välilyönti. 
}; echo ;}

function TestaaMuuttuja () { 
[[ $(eval echo \${!$1[*]} | cut -sd ' ' -f 2) ]] && TulostaMatriisi $1 && return # Matriisi ei voi olla määrittelemätön vaan silloin se on tavallinen muuttuja.
[[ $1 ]] && TulostaMuuttuja $1 
# [[ $(eval echo \$$1) ]] && TulostaMuuttuja $1
echo
}

# function Xref () { # echo -e "Xrefiä on kutsuttu skriptistä:"${0}".   Kutsu tehtiin riviltä:"${BASH_LINENO[0]}"\n\n"
for skriptin_listaus in $(cat "${0}")   
do
  [[ $skriptin_listaus = TestaaMuuttuja ]] && break              
  [[ ! $skriptin_listaus = *[\=]* ]] && continue                     # jos rivillä ei ole yhtäkuinmerkkiä niin rivin voi ohittaa 
  [[ ${skriptin_listaus:0:1} = \$ ]] && continue                     # tavallisesti muuttuja ei voi alkaa merkillä $. 
  MUUTTUJAN_NIMI=$(echo ${skriptin_listaus%%=*})                     # muuttujan nimeksi tulee merkit ennen yhtäkuinmerkkiä 
  [[ $MUUTTUJAN_NIMI = *[[:lower:]]* ]] && TestaaMuuttuja $MUUTTUJAN_NIMI # jos muuttujanimestä löytyy yksikin pieni aakkonen niin Xref hyväksyy sen 
  # [[ ${MUUTTUJAN_NIMI:0:1} = [A-Z] && ${MUUTTUJAN_NIMI:1} != [A-Z] ]] && TestaaMuuttuja $MUUTTUJAN_NIMI         # isolla kirjoitetut yksimerkkiset muuttujanimet hyväksytään 
doneIP="17.255.8.44"; for n in {0..255}; do echo $IP | grep -w $n; done | [[ $(wc -l) = 4 ]] && echo IP is ok || echo IP is not ok

apu=$(cat "${0}" | grep function ); [[ $apu > 0 ]] && echo "listaus skriptin funktioista:" &&  echo -e ' '"${apu[@]/%/\n}"  
}  
!
**
Kumpikohan tekee enemmän vaaratilanteita: maadoitus vai maadoittamattomuus? Koko elämäni sähkölaitteita korjattuani voin sanoa että vastaus yllättää varmasti. Sitäpaitsi pahakaan sähköisku ei yleensä tapa vaan se tappovaikutus tulee jostain muusta jota en ala arvelemaan. Voi ehkä väittää että maadoittamattomuus aikaansaa enemmän häiriötoimintoja mutta tiedä häntäkään. ESD-suojausta olen korjaus-hommissa käyttänyt aina kun se on mahdollista koskei siitä haittakaan ole, mutta sitä en voi sanoa onko se tarpeellista edes herkimpien komponenttien kanssa.
**
BASH:ista kertovat oppaat eivät edes mainitse BASH:in tärkeintä käskyä enkä ole tajunnut että asiahan kaipaa selvittämistä: kun BASH:in koodi-rivillä lukee yksikseen: $muuttuja  niin se tulkitaan käskyksi: mene suorittamaan funktiota jonka nimi on muuttujassa ja suoritettuasi funktion palaa tätä käskyä seuraavan käskyyn. Kun BASH:ia alkaa käyttämään ei funktioita tehdä itse joten käskyllä ei olekaan alussa oikein mitään mieltä. Mutta kun funktioita alkaa käyttämään tulee käskystä nopeasti peruspilari.

Mikäli muuttuja on lisäksi assosiatiivisen matriisin jäsen niin saadaan samalla tehtyä 'koodimuunnos'. Lisäksi muuttujan eteen voidaan laittaa ehto: [[ ehto ]] && $muuttuja
- myös sisäisiä funktioita voi kutsua: apu=ls; $apu. Muuten parametreja annettaessa ei saa laittaa lainausmerkkejä: apu=ls *; $apu
**
BASH:ista kertovat oppaat opettavat tekemään sekasotku-koodia; ilmeisesti tarkoitus on esittää kuinka huono ohjelmointikieli BASH on. Ne eivät edes mainitse kuinka skriptin saa esitettyä niin ettei se olisi käsittämätön sekasotku - edes sekasotku-skriptin tekijä ei koskaan oikein käsitä tekosiaan ja vuosien kuluttua sekasotku-skriptit ovat kaikille täysi mysteeri. Käsitettävään skriptiin tarvitaan ennenkaikkea kahta asiaa:

1. käytetään yksinomaan tarpeellisen pitkiä ja kuvaavia nimiä - jos skriptisi kaipaa kommentteja niin se on yleensä kelvottomasti kasattu.
- muuttujan tai funktion nimessä ei voi olla välilyöntiä ja välilyönnin tilalla voikin käyttää alleviivausta (elikä _). Sensijaan tiedostonimi jossa ei tarvittaessa käytetä välilyöntejä tökkivät pahasti. Skandeja ja erikoismerkkejä on syytä välttää: muuttujanimissä ne toimivat ainoastaan kun niiden edessä on kenoviiva; funktionimissäkään välilyönti ei toimi ja vaikka skandit toimivatkin niin ne sekoittavat editorin. Tiedostonimissä voi olla kaikkia muita merkkejä paitsi / , mutta erikoismerkkejä kannattaa niissäkin välttää. 

2. kun samaa toimintaa tehdään useammalla rivillä niin nuo rivit erotetaan omaksi funktiokseen. Funktiota voidaan kutsua joko kirjoittamalla sen nimi tai mainitsemalla muuttuja jonka sisältö on tuon funktion nimi - funktion parametrit voivat olla muuttujassa mukana tai ne voidaan kirjoittaa erikseen.
**
BASH:illa tosiaan tuntuu onnistuvan mikähyvänsä. Tietenkin ongelmia tulee: pahimpiin ongelmiin olen saattanut kuluttaa viikkotolkkua töitä - olen etsinyt kaikkialta ja kokeillut itsekin enkä sittenkään ole löytänyt ratkaisua vaikka olen monia vuosia yrittänyt. Kunnes tehdessäni jotain muuta törmään siihen kuinka se alkuperäinen ongelma ratkaistaan. Ja ratkaisut ovat aina helppoja - mutta ratkaisut vaativat usein sitä että käy ratkaisemaan ongelmaa täysin toisenlaisella vanhojen tottumuksien mukaan arvosteltuna "idioottimaisella" tavalla.
 
Esimerkiksi skriptiajuria on aina vaivannut se, että joskus se yrittää editoida lukkotiedostoja. Ei ole koskaan tullut mieleen että se ettei find-ohjelma hyväksy regex:iä ei tarkoita sitä ettei find-ohjelma tuntisi regex:iä. Mutta findille täytyy kertoa se: find $HOME -regex '.*[a-z]' 
- käsky selväsanaisena: etsi tiedostot joiden nimissä on ainakin yksi pieni kirjain.  
**
Samanlaisten rivien poistamiseen BASH:issa on käsky uniq, mutta tekstinkäsittelyyn se on jokseenkin sopimaton. Sensijaan kannattaa käyttää seuraavia awk-käskyjä:
awk '!x[$0]++'          # poistaa tiedostosta duplikaattirivit
awk '{$1=$1} !x[$0]++'  # poistaa ensin välilyönnit ja tab:it rivien alusta ja lopusta
awk '!NF || !x[$0]++'   # poistaa tiedostosta duplikaattirivit jättäen tekstin tyhjät rivit rauhaan 

grep -Poz  '(?ism:.*BEGIN.*?END)' /boot/grub/grub.cfg         # jaetaan kappaleisiin - ei tee mitään?
**
Dokumentti muodostuu kappaleista. Eri kappaleissa saa yleensä olla samanlaisia rivejä joten vain kussakin kappaleessa sen omat duplikaatti-rivit voi poistaa. Tämänvuoksi dokumentin jokainen kappale täytyy erottaa omaan tiedostoonsa, suorittaa niille duplikaattien poisto ja koota sitten tiedostot yhteen. Tämä täytyy tehdä kahdessa vaiheessa sillä ensimmäinen vaihe tehdään tilanteesta riippuen erilailla:
1. Kun kappaleen alkurivillä on jotakin kappaleelle ominaista; esimerkiksi koodissa sana BEGIN. 
sed  '/kappaleelle_ominaista/ilisätty_rivi' tiedosto_jossa_kappaleet_ovat > /tmp/delmee0
2. Kun kappaleiden välissa on tyhjä rivi:
sed 's/^$/lisätty_rivi/g' tiedosto_jossa_kappaleet_ovat > /tmp/delmee0

Näin aikaansaatu aputiedostosta kappaleet sitten jaetaan omiin tiedostoihinsa:
awk -v RS="lisätty_rivi" '{ print $0 > "/tmp/delmee"NR }' /tmp/delmee0

kappaleet liitetään yhteen tiedostoksi( perättäiset tyhjät rivit supistetaan yhdeksi): 
rm -f /tmp/delmee; n=1; while true; do [[ -f /tmp/delmee$n ]] && { awk '!NF || !x[$0]++' /tmp/delmee$n > apu; cat -s /tmp/delmee apu >> /tmp/delmee ; ((n++));} || exit; done

lopuksi siistitty tiedosto on paikassa: /tmp/delmee
**
Taas kertaalleen jouduin tekemään uuden testin IP-osoitteille sillä monimutkaisemmat regex:ät tökkivät, BASH_REMATCH ei innosta ja yleensä testit lisäksi vuotavat. Hyvä IP-testi onkin ihan perus-käskyistä väsätty ja sellainen mikä ei päästä läpi mitään jossa on fyysistä vikaa muttei myöskään anna vääriä hälytyksiä:
IPv4=1234:0:9012:3456; [[ $(echo $IPv4 | tr -d :[0-9]) = '' && $(echo $IPv4 | tr -dc : | wc -c) = 3 && $(echo $IPv4 | grep -o '[0-9]*' | wc -L) < 5 ]] && echo kunnossa on || echo tökkii
Pätevä IPV4-osoitteen testi: echo "otsikko 456:789:0:123 kkkkkk" | grep -Po '[0-9]\{1,4\}:[0-9]\{1,4\}:[0-9]\{1,4\}:[0-9]\{1,4\}'
- rajoittimen automaattinen määritys: IPv4=1234:0:9012:3456; rajoitin=$(grep -o . <<<$IPv4 | sort -f | uniq -ic | head -1 | awk '{print $2}'); echo $rajoitin
- toinen tapa: function verifyIP() { local o='(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])'; [[ $1 =~ ^$o\.$o\.$o\.$o$ ]]; }; ipv4testi 255:0:012:56 && echo ip hyvä || echo ip kelvoton 
** 
Kaikki ihmisen teot apinoivat aikaisemmin tehtyä, joten on syytä olettaa että IPv6-osoite tarkistetaan melkein samalla tavalla kuin IPv4-osoite. Mutta aletaanpa alusta:

Täydellinen IPv6-osoite on esimerkiksi: 2001:0db8:0000:0000:0000:ff00:0042:8329 
- siten IPv6-osoitteessa voi olla korkeintaan 7 kappaletta :-merkkien eroittamaa ryhmää ja hexdigitejä kussakin ryhmässä korkeintaan 4
Jokaisesta ryhmastä etunollat voi poistaa: 2001:db8:0:0:0:ff00:42:8329
Perättäiset 0:t voi yhdistää kahdeksi perättäiseksi :-merkiksi olipa niitä nollia kuinkamonta vaan joten saadaan: 2001:db8::ff00:42:8329
- esimerkiksi loop-back osoite: 0000:0000:0000:0000:0000:0000:0000:0001 voidaan kirjoittaa ::1
- tarkistus siis IPv6:nkin kanssa kolmivaiheinen:
1. tarkistetaan ettei laittomia merkkejä ole.
2. tarkistetaan että kenttiä on korkeintaan 8 elikä 7:n :-merkkiä
3. tarkistetaan että jokaisessa kentässä on korkeintaan 4 hexdigitiä.

Siis IPv6-osoite saadaan tarkistettua käskyllä joka on melkein sama kuin IPv4:llä mutta parametreja täytyy kyllä hieman muuttaa:
IPv6=01:0db8::ff:42:29; [[ $(echo $IPv6 | tr -d :[[:xdigit:]]) = '' && $(echo $IPv6 | tr -dc : | wc -c) <7 && $(echo $IPv6 | grep -o '[[:xdigit:]]*' | wc -L) < 5 ]] && echo kunnossa on || echo tökkii
- rajoittimen automaattinen haku on aivan samanlainen kuin IPv4:llä.
- huomioi että vain fyysiset virheet voi selvittää näin ja loogisiin virheisiin kompastutaan jokatapauksessa.
**
# tarkoituksena on listata kotikansiosta tiedosto-niminen tiedosto siten että siinä olevat ipv4-osoitteet tulostetaan punaisella muun tekstin ollessa mustaa. 

# ensiksi funktio joka kertoo onko sille varmastisyötetty ipv4-osoite:
function ipv4testi () { for n in {0..255}; do echo $1 | grep -wo 0*$n; done | [[ $(wc -l) = 4 ]] ;}

# etsitään tiedostosta ne numerosarjat jotka saattaisivat olla ipv4 osoitteita ja talletetaan niistä muodostuva lista kovalevylle: 
grep -Po '[0-9]{1,4}:[0-9]{1,4}:[0-9]{1,4}:[0-9]{1,4}' ~/tiedosto > /tmp/delme1 

# lopuksi tarkistetaan listan jäsenet yksitellen ja tehdään kovalevylle uusi lista hyväksytyistä:
echo '' > /tmp/delme2; while IFS=$'\n' read -r rivi; do ipv4testi $rivi && echo $rivi >> /tmp/delme2; done < /tmp/delme1

# listataan tiedosto merkiten siihen ipv4-osoitteiksi hyväksytyt:
grep --color -E $(cat /tmp/delme2 | tr '\n' \|) ~/tiedosto   
**
# tarkoituksena on listata kotikansiosta tiedosto-niminen tiedosto siten että siinä olevat ipv4-osoitteet tulostetaan punaisella muun tekstin ollessa mustaa.

# ensiksi funktio joka kertoo onko sille syötetty varmasti ipv6-osoite:
function ipv6testi () { [[ $(echo $1|tr -d :[[:xdigit:]])='' && $(echo $1|tr -dc :|wc -c)<7 && $(echo $1|grep -o '[[:xdigit:]]*'|wc -L)<5 ]];}

etsitään tiedostosta ne jotka saattaisivat olla ipv6 osoitteita ja talletetaan ne levylle:
echo 201:0d8:000:000:00a0:ff0:0042:832 | grep -P '::[[:xdigit:]]|:[[:xdigit:]]{1,4}:' > /tmp/delme1

# tarkistetaan listan jäsenet yksitellen ja tehdään kovalevylle uusi lista hyväksytyistä:
echo '' > /tmp/delme2; while IFS=$'\n' read -r rivi; do ipv6testi $rivi && echo $rivi >> /tmp/delme2; done < /tmp/delme1

# lopuksi tarkistetaan listan jäsenet yksitellen ja tehdään kovalevylle uusi lista hyväksytyistä:
echo '' > /tmp/delme2; while IFS=$'\n' read -r rivi; do ipv6testi $rivi && echo $rivi >> /tmp/delme2; done < /tmp/delme1
**
Toimii ipv4:n kanssa:
#!/bin/bash
# tarkoituksena on listata kotikansiosta tiedosto-niminen tiedosto siten että siinä olevat ipv4-osoitteet ovat tulostettu punaisella muun tekstin ollessa mustaa.
export GREP_COLOR="01;31" # red; 32=green; 33=yellow; 34=blue; 35=purple # 16 toimii
# ensiksi funktio joka kertoo onko sille syötetty tosiaankin ipv4-osoite:
function ipv4testi () { [[ ! $(echo $1 | grep ::) ]] && [[ $(echo $1 | grep [:0-9]*) ]] && [[ $(echo $1 | awk -F':' '$1<255 && $1>=0 && $2<255 && $2>=0 && $3<255 && $3>=0 && $4<255 && $4>=0 && $5==""') ]] ;}

# etsitään tiedostosta ne numerosarjat jotka saattaisivat olla ipv4 osoitteita ja talletetaan niistä muodostuva lista kovalevylle:
grep -Po '[0-9]*[:0-9a-zA-Z]*' ~/tiedosto > /tmp/delme1

# tarkistetaan listan jäsenet yksitellen ja tehdään kovalevylle uusi lista hyväksytyistä:
echo '' > /tmp/delme2; while IFS=$'\n' read -r rivi; do ipv4testi $rivi && echo $rivi >> /tmp/delme2; done < /tmp/delme1

# listataan tiedosto merkiten siihen ipv4-osoitteiksi hyväksytyt:
grep --color -E $(cat /tmp/delme2 | tr '\n' \|) ~/tiedosto
read -p 'paina enter jatkaakseesi'
**
tekstilohko on osa tekstiä jota ympäröivät jotkin rajoittimet (tag:it). Esimerkiksi kirjassa on kappaleet ja ne ovat tyhjien rivien ympäröimiä rivijä - tyhjän rivin asemesta voi käyttää mitähyvänsä
merkkejä: nettisivuilla on usein: << ja: >> , mutta ihan kivasti sopii myös merkki ** merkitsemään vanhan lopua ja uuden alkua. Mikäli käytetään jotakin merkkiä niin silloin ei merkitse mitään
koostuuko teksti riveistä ollenkaan vai onko kaikki yhdessä pötkössä.
rajoittimet voivat olla tekstiä tai jokin regex 
- lohkoja eroteltaessa kannattaa aina toimia yksinkertaisimmalla tavalla joka toimii.

BASH:issa rajoittimien ympäröimä teksti erotetaan käskyllä(tässä rajoittimina on: >> ja: <<): 
   echo 'jotakin roskaa alussa <<...tekstiä ja siinä saa olla välilyöntejäkin...>> jotakin roskaa lopussa' | grep -o '<<.*>>'
tai toimittaessa tiedostojen kanssa
   grep '<<.*>>' tiedosto 
tämä tiedosto-käsky käy automaattisesti läpi koko tiedoston rivi kerrallaan ja soveltaa käskyä siihen.
jokatapauksessa tämä ottaa mukaan kummankin eroittimen
mikäli jompaakumpaa eroitinta ei löydy ei myöskään tulosteta mitään.

Mutta mikäli rajoittimia ei haluta tulosteisiin mukaan niin käsky onkin:
   echo 'jotakin roskaa alussa <<...tekstiä ja siinä saa olla välilyöntejäkin...>> jotakin roskaa lopussa' | grep -Po '(?<=<<).*(?=>>)'
tai tiedostolla:
   grep -Po '(?<=<<).*(?=>>)' tiedosto
kovien lainausmerkkien välinen teksti tulkitaan aina kirjaimellisesti.
 rajoittimet saavat ola samojakin:
   grep -Po '(?<=:).*(?=:)' tiedosto        

mikäli rajoittimien välinen teksti sisältää rivinvaihtoja muuttuu käsky (nyt toimitaan aina tiedostojen kanssa):
   grep -Poz  '(?ism:BEGIN.*?END)' /boot/grub/grub.cfg
eroittimet tulevat mukaan. 
mikäli jompaakumpaa eroitinta ei löydy ei myöskään tulosteta mitään. Tai voi käyttää käskyä: 
   sed -n '/BEGIN/,/END+/ { p }' /boot/grub/grub.cfg   
joka tulostaa lohkojen väliin tyhjän rivin
rivejä ennen ensimmäistä rajoitinta ja viimeisen rajoittimen jälkeen ei tulosteta. Lohkot voi tulostaa näinkin:
   lspci -v | awk '/VGA/,/^$/'  # lohkon alku on VGA ja loppu tyhjä rivi. Tulostaa muuten jokaisen lohkon joka alkaa VGA
- tuo ^$ merkitsee tyhjää riviä


Lohkoja voikin käsittellä mitenkä hyvänsä jos pystyy pukemaan tehtävän sanoiksi. Näitä tämäntyyppisiä käskyjä on lukemattomia, niiden muodostaminen on hidasta eikä ole mahdollista muistaa niistä oikeastaan mitään. Käskyvarasto onkin täysin pakollinen ja täytyy olla jokin keino löytää sieltä haluamansa. Jos käskyvarastoa ei ole niin käy juuri niin kuin BASH:ille on käynyt. Muut kielet porskuttaa juuri sentakia että niissä nuo varastot on hoidettu edes jollaintavoin. Seuraavat käskyesimerkit eivät oikeastaan ole esitetty senvuoksi että ne olisivat hyödyllisiä, vaan senvuoksi että tuo käskyvaraston pakollisuus selventyisi. Käskyesimerkkkejä: 

1. Mikäli teksti muodostuu lohkoista niin todennäköisemmin haluttaessa poistaa samanlaiset rivit halutaan poistaa toisinnot vain kunkin lohkon sisällä. Siihen sopiva käsky on:
ensin jaetaan tiedosto ali-tiedostoiksi tyhjien rivien kohdilta: 
   awk -v RS='' '{ print $0 > "/tmp/delmee"NR }' ~/koe2
sitten käsitellään muodostetut ali-tiedostot ja kootaan tulos taas yhteen:
   echo '' > /tmp/delmee_kokonaisuus; n=1; while true; do [[ -f /tmp/delmee$n ]] && awk '{$1=$1} !x[$0]++' /tmp/delmee$n >> /tmp/delmee_kokonaisuus || exit; ((n++)); done
- lopputulos on tiedostossa: /tmp/delmee_kokonaisuus

2. Kun halutaan tulostaa tiedostosta /boot/grub/grub.cfg ne BEGIN- ja END-rajoittimien väliset lohkot, joiden jollakulla rivillä lukee: source niin käsketään:
   sed -n '/BEGIN/,/END+/ { p }' /boot/grub/grub.cfg | awk -v RS='' '/source/ {print $0"\n"}'
**
BASH-skriptit ovat hitaita. Jos skriptin tekee oikein on se silti harvoin liian hidas - jopa BASH-skriptit ovat nopeampia kuin käyttäjät ja sehän riittää. Sensijaan käyttäjän nynniminen on todellinen hidaste ja juuri silloin kun se merkitsee eniten.

Esimerkiksi BASH:issa on formatointi-ohjelmia jotka tekevät yleensä parempaa jälkeä kuin ohjelmoijat - ja ennenkaikkea ne pystyvät mukautumaan käynninaikaisiin muutoksiin. Ja silti näitä formatointi-ohjelmia ei käytetä vaikka ne saa liitettyä koodiin salaman-nopeasti verrattuna siihen että muodostetaan formatointi määreitä.
**

Seuraa kovalevy-tilan käyttöä            - tavalliset ja piilotiedostot erikseen  
Seuraa tiedostojen määrää                - tavalliset ja piilotiedostot erikseen ja systeemi- ja kotiosio erikseen
Ylläpidä listaa siitä mitä koneessasi on - tavalliset ja piilotiedostot erikseen

Seuraa omituisia oikeuksia
Seuraa tiedostojen lisä-attribuutteja
**
Ihmiset ovat tyytymättömiä BASH-skripteihin kun ne ovat niin hitaitakin. 
Sanotaampa että sinulla on skripti jonka suoritus kestää 5 sekuntia. Sen  minun nopeuttamisessa on kammottavan iso työ eikä tämmöinen väsynyt vanhus siihen oikein enää kykene. Mutta miltä tuntuu 5ms?
Sillä sellaisista eroista on kyse mikäli hitauden syynä on BASH. 
**
clear; echo -n 'viimeksi käsitellyt 40 kotikansiosi tiedostoa esittämättä piilotiedostoja:';find ~ -type f  -printf '%T@ %p\n' 2>/dev/null | grep -v '/\.' | sort -n | grep -v kirjoita_tähän_mitä_et_halua_tulosteeseen | tail -40 | cut --output-delimiter='  ' --complement -c 11-$((29+${#USER}))

Pelkäänpä että komentoriviä vierastetaan koska luullaan että siinä joutuu näpyttelemään paljon. Näpyttelyä siinä on vähän kunhan pääsee alkuun. Oppirahat ovat ihan yhtä kalliit kuin älypuhelimen käytön opettelussa; mutta eivät siis kalliimmat. Ja sekin pitää paikkansa että useimmille komentorivistä ei ole juurikaan hyötyä mutta joillekin harvoille se on parhaimpia työkaluja. 
**
Sainpa kehitettyä yksirivisen skriptin joka laskee tiedostosta tagien välisten merkkityhmien pituudet. Tämmöisten merkityshän on sinällään melkein olematon, mutta
on osoittautunut että tämmöisiin ongelmiin löytyy poikkeuksetta tällaisia nopeita skriptejä: nopeutta tulee lisää parikymmenkertaisesti ja koodikin supisuu melkein olemattomaksi.
Skriptiajurilla näitä tekee nopeasti. Ongelmana on ainoastaan ymmärtää mitä skriptin tulisi tehdä, osata jakaa se osiin ja osata pyytää skriptiajurilta apua.

grep -Po '(?<=<<).*(?=>>)' ~/tiedosto | awk '{split($0,a,"\n"); for (i = 1; i <= NF; i++) print length(a[i])}'
**
Kaikilla foorumeilla vanhoihin viesteihin vastaamista kehoitetaan välttämään. Se on väärä mielipide kun on kyse ohjelmoinnista: vaikka kysymys olisi jo ratkaistu
eikä uudesta ratkaisusta olisi alkuperäiselle kysyjälle hyötyä niin koko ohjelmoinnille hyöty voi olla suuri.

Tämänpäivän BASH on täysin muuttunut siitä mitä BASH oli aikoinaan, mutta ennenkaikkea nyt voi antaa BASH:in ohjelmien suorittaa ratkaisuja: esimerkiksi awk, sed ja grep...ottaa hyötyä regrex:ist'ä.... Motta siinäkin pitää otta huomioon ettei niistä aina ole mitään apua.

Koska BASH on hylätty käyttökelvottomana eikä uusia ominaisuuksia ole otettu käyttöön ei BASH:ia juuri kukaan osaa käyttää. Siksi on vaikeaa löytää näitä uustyyppisen BASH:in ratkaisuja - varsinkaan kun tukea on vaikea löytää. Niinkuin kaikilla kielillä aloitettaessa koodaaminen. 
**
Ei kai käsky:
sudo apt-get autoclean
voi poistaa vanhoja kerneleitä? Sillä vaikka se olisi erinomainen juttu meille taviksille, niin eikö se olisi tosihuono juttu virtuooseille jotka kääntää laiteajureita? Sillä ainakin ennen kun poisti kerenelin header-tiedostot niin käännökset lakkasivat toimimasta.
- kyllähän ne suunnittelee  tuommoista kokoajan, mitta eihän se voi onnistua vielä pitkään aikaan, sillä käsinkin käännettäessä vastaan tulee useimmiten vaikeuksia jotka vaativat taiteilemaan ennenkuin kääntäminen onnistuu. Automaatti-kääntäjähän on tulevaisuuden asia?
- minä en voi testata sillä koneeni päivitys jättää koneeseeni aina vain yhden kernelin koska en harrasta käännettyjen modulien käyttöä.
**
Skriptien toiminta on hyvä jakaa funktioihin jotta rakenteesta saisi selväpiirteisen. Mutta jako funktioihin on hyvä tehdä toisestakin systä: kaikki skriptit nynnivät aina jossakin. Jaettaessa skriptiä tehtäessä skripti funktioihin kyetään funktiot tekemään siten että skriptin ajamisen jälkeen saadaan jokaisesta funktiosta tuloste siitä monestiko funktiota on kutsuttu ja kutsuissa kulunut kokonaisaika. 
**
Vaikka loopit ovat oleellisia rakennusosia myös BASH-skripteissä ei BASH-koodiin saa looppeja tehdä, vaan aina tulee käyttää sitä "automaatti-looppia" joka on awk, sed, grep ja useissa BASH-käskyissä sisäänrakennettuna. Sillä BASH-koodilla toteutetut loopit hidastavat skriptiä ja koodia saa näpytellä lisää monta riviä.
Myös nämä "automaatti-loopit" osaavat hyödyntää regex:iä.
 
Esimerkiksi kun halutaan tulostaa matriisin pisimmän jäsenen pituus voi toteutus olla seuraavanlainen:  
function matriisin_pisin_jäsen () { echo $(($(eval echo -e "' '\${$1[@]/%/\\\n}" | wc -L)-1));}; matriisi=(aaaa a aaa aa); matriisin_pisin_jäsen matriisi

tai mikäli on "eval-vihamielinen" niin voi käskeä:
function matriisin_pisin_jäsen () { set "$1"; echo $@ | tr ' ' '\n'| wc -L ;}; matriisi=(aaaa a aaaaa aa); matriisin_pisin_jäsen "$(echo ${matriisi[*]})"

Linux oli aikoinaan tarkoitettu tiedostonkäsittelyyn. Tiedostoja käsitellään rivi kerrallaan alkaen riviltä 1 ja siitä eteenpäin järjestyksessä loppuun asti. Tämä toimintatapa on sisäänrakennettuna joissain BASH-käskyissä ja kaikissa awk, sed, grep ... käskyissä. BASH:iin ei pidä koodata "selväkielistä looppia" vaan jos käskyssää ei ole tätä "automaatti-looppia" niin "selväkielinen looppi koodataan yleensä awk:illa.  



Esimerkki awk:in automaatti-loopista:
awk -F: '/home/&&/bash/ {print $1}' /etc/passwd

Esimerkki BASH:in oman käskyn automaatti-loopista:
tail -10 tiedosto


Esimerkki siitä kun on pakko koodata "selväkielinen looppi":
echo 1 2 3 4 5 | awk '{for(i=1;i<=NF;i++) t+=$i; print "rivin summa: ",t; t=0}'


