Näytä kirjoitukset

Tässä osiossa voit tarkastella kaikkia tämän jäsenen viestejä. Huomaa, että näet viestit vain niiltä alueilta, joihin sinulla on pääsy.


Viestit - petteriIII

Sivuja: [1] 2 3 ... 35
1
iki-vanhojen tekstinkäsittely-käskyy ovat uusia käskyjä yli kymmynen kertoo nopeampia ja koska tulkki tykkää niistä niin joukkona niiden nopeus nousee edelleen. Siis kuka pääkallon-paikan suurista virtuooseista hylkäsi nuo vanhat käskyt niin ihan yksin hän hidasti BASHa yli kymmenkertaisesti, teki desimaalilaskennan mahdottomals, esti nimi-parametrien käytön ja parrametrien palauttamisen.... - ja samalla älytti virtuooseja niin pahasti että nämä mieluummin antoivat BASH:in tuhoutua kuin tunnustivat että heitä oli älytetty.

Potenssiin korottamisen funktiossa  noide käskyjen nopeuden taas kerran huomasin - tässä tapauksessa laskussa: -1.234567890123 ^ 10 - edes noin tarkoista laskuista ei normaali-komennoilla voi uneksiakaan. Nimittäin tuollaisia laskuja laskevan funktion vanhassa toteutuksessa sen 50:stä lauseesta yksi oli uusmuotinen koska en aikoinaan tiennyt että sillekin löytyy korvaava tekstijono-komento - silloin lasku kesti 15 ms. Kun sen yhden komennon muutti tekstijono-komennoksi niin koko funktion nopeus nousi viisinkertaiseksi elikä 3ms:iin. BASH:iksi nopeus on vallankumouksellinen - mutta on vielä liian aikaista tehdä mitään tarkempia johtopäätöksiä.
- funktio löytyy paikasta: https://forum.ubuntu-fi.org/index.php?topic=303.msg447967#msg447967

---

Desimaalilukujen kertolaskussa tuloksen numerot tulevat oikein kun desimaalipisteen poistaa sekä kertojasta että kerrottavasta ja suorittaa kertolaskun senjälkeen - joten lopputulos on täysin oikea jos siihen saa sijoitettua desimaalipisteen oikealle paikalle. Tämän oikean paikan laskeminen on yksinkertaista. Mutta numeroiden käsittelyssä on ehdottomasti käytettävä yksinomaan tekstijono-komentoja - varsinaiset kertolaskut kylläkin suoritetaan BASH:in kokonaisluku kertojassa.

Koska tuloksen täytyy yksinkertaisessa versiossa mahtua 18 numeroon niin kerrottavat luvut voivat olla korkeintaan 9 merkkisiä. Koska tarkkuus jäisi tällöin kovin vaatimattomaksi käytetään kaksinkertaista tarkkuutta joten sekä kertoja että kerrottava voivat olla 18 merkkisiä liukulukuja jolloi tulos voi olla 32 merkkinen liukuluku. Kansakoulu tasoista matematiikkaa kaksinkertainen tarkkuuskin on.

Kerro18 löytyy esimerkiksi paikasta https://forum.ubuntu-fi.org/index.php?topic=303.msg448022#msg448022
- jos haluat kokeilla sitä niin leikkaa sen koodikenttä kokonaisuudessaan, liimaaa se päätteeseen ja paina enter
- voit antaa nyt laskuja itsekin - esimerkiksi kirjoita: kerro18 12345678.87654321 87654321.12345678
- desimaalisten liuku-lukujen kaikki muutkin perus-laskutoimitukset toimivat jo silloin kun BASH oli ihan nuori. Virtuoosit eivät vain osanneet kasata niiden funktioita - kyse on tiedosta että ne voi tehdä kuten kuvattiin - eikä taidosta sillä laskut ovat yksinkertaisia.
- eihän tämmöisillä nykyään mitään arvoa nykyään ole mutta silloin kun BASH:ia alettiin romuttamaan ne olisiva olleet BASH:issa tarpeen. Ja kuka tietää onko tämä vaihe vasta alkua? Onko tämäkin kieli joka ei suostu kuolemaan?
- pahin vaikeus laskussa on löytää oikeat tekstijono-komennot sillä BASH-raamatussakin on vain muutama. Tuntuu tosiaan siltä että parhaat komennot on heitetty roskikseen jotta desimaali-laskuja ei voisi tehdä ja BASH:ia voisi mollata paremmin.
- tietokoneiden matematiikka-prosessoritkin aikoinaan toimivat kertolaskussa aikoinaan samoin kuin kerro18.

---

Aina kun skripti toimii - ja silloinkin kun on toimimatta - niin BASH vaanii monia tapahtumia - matematiikka-skriptissä näitä kahta asiaa:

1. koettaa löytää skriptirivin ensimmäistä sanaa massamuistin $PATH nimisen muuttujan osoittamista kansioista senjälkeen kun on lauseen lopussa painettu enter - niissä kansioissa olevat tiedostot on nimetty käskyjen nimillä. Kansiot käydään läpi siinä järjestyksessä missä ne on annettu muuttujassa $PATH - ja sitä käskyä käytetään joka ensiksi löytyy sillä useissakin kansioissa voi olla sama käsky toteutettuna hieman eritavalla - ja jos kirjoittaa käskyyn polunkin niin käytetään sitä käskyä.
- luettelon koneesi ohjelmakansioista saat kun kirjoitat: echo $PATH. Sen tulostuksessa merkki : on erote-välilyönti - sillä vaikka tiedostonimessä on harvoin välilyöntejä niin merkkiä : ei voi olla koskaan. Ja:
A. jos nimi löydetään jostakin noista kansioista niin sen osoittama tiedosto suoritetaan ja kaikki sanan perään kirjoitetun oletetaan olevan käskyn tarkentimia elikä 'kytkimiä' mikäli niiden edessä on miinusmerkki ja muuten toiminnan kohdetta. Jos kohteen ensimmäinen merkki voi olla miinus-merkki niin sellaisen kohteen eteen tulee kirjoittaa -- .
- toiminnan tulos tulostetaan kuvaputkelle ellei toisin ole määrätty.
- muuten se löytyvä ohjelma on harvoin BASH-muotoista vaan yleensä ne ovat käännettyä C:tä. Siten BASH:in käskyt ovat yleensä ällistyttävän nopeita - vain skripti kokonaisuudessaan on ällistyttävän hidas - ja hitautta lisää se että skriptit tehdään niin että tulkkia kutsutaan jokaisen käskyn jälkeen. En ole saanut tarkasti selville kuinka kauan tulkin kutsuminen kestää mutta jotain .5 ms se on.
B. jos nimeä ei löydetä niin koetetan löytää sana määritellyistä funktioista
- listan koneesi määritellyistä funktioista saat käskyllä: declare -f . Niitä on jokaisessa koneessa alussa nin 74.
- funktio on normaali skripti joka on kirjoitettu funktiomuotoon: function funktion_nimi { funktion lauseet yksi- tai monirivisenä täysin normaalina skriptinä }
- huomaa {} sulut funktion koodin ympärillä - niitä käytettäessä ei luoda uutta istuntoa ja seurauksena siitä funktio-kutsu kestää vain noin 50mikrosekuntia ja muutujat ovat yhteisiä 'pääohjelmassa' ja funktiossa - siis jos muuttujaa muutetaan toisessa niin se muuttuu toisessakin. Funktiossa voidaan kuitenkin määrätä muuttujan arvon muutoksien kuuluvan vain funktioon - määreellä: local muttujan_nimi
- funktion ympärillä voi olla myös kaarisulut jolloin luodaan uusi istunto. Se kestää paljon kauemmin ja sillä on myös omat muuttujat. Ei tällaisia funktioita käytännössä ole näkynyt - mutta asia on kuitenkin hyvä tietää.
- funktiokutsu voi olla sana, esimerkiksi: function koe () { echo $1 ;}; koe jees pox limited.  Sana koe on se kutsu - ja myös funktion nimi - ja jees kutsun ensimmäinen parametri. Koska jees on ensimmäinen parametri niin funktiossa se nimi on $1. pox on toinen parametri joten se on $2. limited on kolmas parametri elikä $3.
- funktiokutsussa () on merkkinä siitä että parametreja on - monessa paikassa BASH merkitsee säilytyspaikkaa noin - tai yleensä {}.
- funktiokutsu voi olla myös muuttujan sisältö: function koe () { echo $1 ;}; a=koe; $a jees   
- funktiokutsu voi olla myös matriisin nimi tai sisältö ja jopa assisiatiivisen matriisin ja silloin pompun osoite on koodi-muunnettu. Parametreja voi olla kuinka monta vaan eikä niiden tyyppiäkään rajoiteta mitenkään - ne voivat olla myös käskyjä, funktioita ja regex:iä - ne ovat kylläkin vaikeakäyttöisiä.
- funktio voi kutsua mielivaltaisen monia toisia funktioita tai jopa itseään - itseään kutsuvassa funktiosta täytyy löytyä ehto milloin itseä ei enää kutsuta. Funktioketjun pituudelle ei ole tiukkaa ylärajaa. Eikä funktio-nimille juurikaan ole rajoituksia - olemassa olevien käskyjen nimiä kannattaa välttää mutta pakko sekään ei ole ja sellainen funktio korvaakin käskyn - sillä ainoastaan viimeistä määrittelyä käytetään - ja funktion alkuperäinen määrittely palaa voimaan kun pääte suljetaan.
- minkäniminen funktio tahansa voidaan määritellä uudelleen vaikka kuinka useasti ja vain viimeistä määrittelyä käytetään. Uudestaan määrittely ei oikeastaan hidasta mutta muistiahan se vie koska BASH:issa ei automaattista roskankeruuta juurikaan ole - voit kyllä tehdä oman roskankeruu-funktion ja ajaa sitä silloin-tällöin. Samasta syystä todella isojen matriisien uudestaan määrittely on ongelmallista ellei ensin tuhoa matriisin vanhaa määrittelyä käskyllä: unset matriisin-nimi.
-jos nimeä ei löydy määritellyistä funktioistakaan niin suoritetaan funktio: command_not_found_handle ja tehdään mitä se määrää - normaalisti tulostetaan 'commad not found' mutta voisihan sensijaan kutsua muita funktioita. Command_not_found_handle niminen funktio on jokaisen koneen päätteessä aina toiminnassa - katso millainen koneessasi on käskyllä: declare -f command_not_found_handle - se on kaikinpuolin ihan normaali funktioksi kirjoitettu skripti. Muuten tulostamatta jättäminen ei ole sama kuin tulostaa tyhjää joten täytyy kirjoittaa echo '' . Funktiossa on pakko tehdä jotakin tai virhe seuraa - ja esimerkiksi ehdollinen luse joka ei toteudu ei myöskään tee mitään ja siitä tuleekin pottumainen virhe.


- command_not_found_handle niminen funktio on jokaisen koneen päätteessä aina määriteltynä - katso millainen koneessasi on käskyllä: 'declare -f command_not_found_handle' - se on kaikinpuolin ihan normaali funktioksi kirjoitettu skripti. Muuten tulostamatta jättäminen ei ole sama kuin tulostaa tyhjää joten täytyy kirjoittaa echo '' . Funktiossa on pakko tehdä jotakin tai virhe seuraa - ja esimerkiksi ehdollinen lause joka ei toteudu ei se myöskään tee mitään ja siitä tuleekin pottumainen virhe.
- matematiikka-skriptissä command_not_found_handle on määrätty tulostamaan tyhjää - itseasiassa määrätään uudelleen määritelty command_not_found_handle tulostamaan tyhjää - se jonka pitäisi udella: tarkoititko käskyä xxx paketissa yyy
- minkäniminen funktio tahansa voidaan määritellä uudelleen vaikka kuinka useasti ja vain viimeistä määrittelyä käytetään. Uudestaan määrittely ei oikeastaan hidasta mutta muistiahan se vie koska BASH:issa ei automaattista roskankeruuta juurikaan ole - voit kyllä tehdä oman roskankeruu-funktion ja ajaa sitä silloin-tällöin. Samasta syystä todella isojen matriisien uudestaan määrittely on ongelmallista ellei ensin tuhoa matriisin vanhaa määrittelyä käskyllä: unset matriisin-nimi.
- tässä command_not_found_handle on määrätty tulostamaan tyhjää - itseasiassa määrätään uudelleen määritelty command_not_found_handle tulostamaan tyhjää - se jonka pitäisi udella: tarkoititko käskyä xxx paketissa yyy.

---

2. Käskyllä:trap BASH on määrätty virheen sattuessa suorittamaan komento: 'laske "$BASH_COMMAND"'.
- se määrää että virhetilanteessa suoritetaan funktio:laske käyttäen sen parametrina muuttujaa nimeltä: "$BASH_COMMAND" (se on BASH:in itsensä tekemä muuttuja ja sen voi vain lukea muttei kirjoittaa normaalilla tavalla - esimerkissä muuttujassa on se näpytelty teksti: 1+1. Tästä syystä näpytellyssä tekstissa ei saa olla kaarisulkuja vaan on käytettävä hakasulkuja.)
- huomioi muuten että myös se funktio command_not_found_handle toimii ja saattaa kirjoittaa: command not found. Laskenta kuitenkin alkaa mutta koska BASH on hidas saattaa näyttö pysyä muuten tyhjänä kauankin joten täytyy olla kärsivällinen - kyllä se tuloskin joskus tulee.

---

Käytännössä kohdattavia muita trap-komentoja:

Koodia: [Valitse]
trap 'echo virherivi:${LINENO[@]}; echo funktiossa:¨${FUNCNAME[@]}" ; read' ERR
trap 'rc=$?; echo "virhekoodi $rc rivillä $LINENO-${FUNCNAME[0]}" ' ERR
trap ' (( $? )) && echo ${FUNCNAME[0]}" palautti virheen:"$?'  RETURN
trap "echo kutsupino: ${FUNCNAME[@]}" ERR                      # kun funktiot kutsuvat toisiaan niin kerrotaan ne funktiot joiden kautta virheeseen päädyttiin.
trap pomppaaTänne SIGINT                                       # mitä tehdään kun painetaan CTRL-c
trap 'echo "Control-C disabled."' 2
trap jälkiensiivous SIGTERM                                    # kun skripti loppuu tai tekee suoritusaikaisen virheen mennään fumktioon: jälkiensiivous
trap 'echo "VARIABLE-TRACE> \$variable = \"$variable\""' DEBUG # muuttujan arvon seuraaminen
set -x; trap "echo hit_return;read x" DEBUG                    # käskyrivien suoritus yksi kerrallaan

2
Vaikka monet BASH-skripti toimivatkin useimmissa koneissa niin harvat BASH-skriptit toimivat kaikissa koneissa - ja siihen on syynä muunmuassa:
1. Kaikki maailman 7miljoonaa linux-jakelua on koottu eritavoin miljoonasta matalan tason paketista ja jokaisen paketin kohdalla arvioidaan että: tarvitaankohan tämmöistä pakettia tässä jakelussa vai jätetäänkö pois? Sillä useimpien poisjättöjen vaikutukset ovat todella vähäisiä mutta jossain vaiheessa aletaan nilkuttaa.
2. BASH:kaan ei ole eri jakeluissa läheskään sama vaan kaikkiin jakeluihin on ladattu mitkä korkeamman tason paketit milloinkin joten jos skripti toimii yhdessä masiinassa ei se välttättä toimikaan toisessa - yksittäistä käskyä kun yritetään suorittaa niin puuttuvan paketin lataamisesta tulee kyllä lataamisohje - jos luoja suo - mutta sripteissä ei lataamisohjeita voi antaa - ne eivät vaan toimi.
3. Virallisten pakettilähteiden laatu ja päivitettävyys on hyvä mutta epävirallisilla joskus surkea - yleensä niillä on joku ylläpitäjä mutta ei aina - joten epäviralliset saattavat myös lakata toimimasta varoittamatta. Ja siitähuolimatta epäviralliset tuhoavat ihmisten halun yrittää itse sillä itse ei saa aikaiseksi mitään läheskään yhtähyvää.
- Linux/BASH:in kirous onkin niiden liioiteltu monipuolisuus - epäilenpä että Linuxin viholliset lisäävät tuota monipuolisuutta sillä se johtaa siihen ettei kukaan hallitse koko BASH-orkesteria eivätkä ainakaan pysty enää opettaamaan tulevia sukupolvia.
- lohdullista on se että pienin muutoksin samat ohjeet toimivat kaikissa jakeluissa - valitettavasti kestää vuosia oppia mitä täytyy muuttaa milloinkin.
- koska linuxin suuret gurut eivät halua että linuxiin tulisi paljon viruksia niin he ilmeisesti haluavat pitää linux:in hankala-käyttöisenä muille kuin virtuooseille - ettei se viruksien tekeminen olisi pahiksille kannattavaa kun linux ei ole kovin suosittu taviksien keskuudessa.
- BASH:iin tulee harvoin BASH:in ylläpitäjien toimesta päivityksiä - ja teoria on että ne ainoastaan korjaavat jotakin mutta todellisuus on se että ne samalla muuttavat jotakin - mutta korjaukset ovat yleensä pieniä ja niitäkin taitaa tehdä vain Chet Ramey ja ilmeisesti hänkin tekee ne harkiten - elikä BASH:issa on edes jotain melko vakaata.


Halusin kuitenkin tutkia toimiiko yli vuosikymmen sitten tekemäni päätteestä ohjelmoitavan funktiolaskimen tekevä skripti ilman muutoksia täysin samoin kuin ennen - sillä skripti vaatii koneelta paljon. Kyllä se toimii.

Toiminta jotta saisit skriptin koneeseesi: näpäytä hiirellä seuraavaa käskyä ja paina enter:
https://forum.ubuntu-fi.org/index.php?PHPSESSID=6umrp7jv7kbakkci2rok88h899&action=dlattach;topic=303.0;attach=12583
- mene tämänjälkeen koneesi kotikansion lataukset- tai download nimiseen kansioon ja näpäytä hiiren vasemmalla kansioon ilmestynyttä tiedostoa: laskija.tar.gz
ja avautuvasta valikosta näpäytä hiiren oikealla: 'pura tähän' tai extract jolloin samaan kansioon ilmestyy skripti:laske (se on skripti sillä päätettä .sh ei toiminta kaipaa)
- näpäytä sitä hiiren oikealla ja avautuvasta valikosta näpäytä: copy
- avaa pääte ja kirjoita: .  ja paina sitten yhtaikaa nappeja shift, ctrl, ja v ja sitten paina enter (ensimmäinen merkki on piste ja sen perässä on välilyönti. Joissakin bash:eissa jätetään tuo shift pois). Jos joskus myöhemminkin haluat kokeilla laskinta niin kirjoita uudestaan tuo sama . ~/laske ja paina enter.
- näennäisesti mitään ei tapahdu mutta laskenta toimii tämän jälkeen - mutta vain tässä päätteessä niinkauan kunnes tämä pääte suljetaan. Sulkemisen jälkeen laskenta-kyky on unohdettu eikä jälki-seurauksiakaan ole.
- siis pysy nyt jatkossakin tässä päätteessä sillä jos vaihdat päätettä niin matematiikka unohtuu.

3
Vaikka monet BASH-skripti toimivatkin useimmissa koneissa niin harvat BASH-skriptit toimivat kaikissa koneissa - ja siihen on syynä muunmuassa:
1. Kaikki maailman 7miljoonaa linux-jakelua on koottu eritavoin miljoonasta matalan tason paketista ja jokaisen paketin kohdalla arvioidaan että: tarvitaankohan tämmöistä pakettia tässä jakelussa vai jätetäänkö pois? Sillä useimpien poisjättöjen vaikutukset ovat todella vähäisiä mutta jossain vaiheessa aletaan nilkuttaa.
2. BASH:kaan ei ole eri jakeluissa läheskään sama vaan kaikkiin jakeluihin on ladattu mitkä korkeamman tason paketit milloinkin joten jos skripti toimii yhdessä masiinassa ei se välttättä toimikaan toisessa - yksittäistä käskyä kun yritetään suorittaa niin puuttuvan paketin lataamisesta tulee kyllä lataamisohje - jos luoja suo - mutta sripteissä ei lataamisohjeita voi antaa - ne eivät vaan toimi.
3. Virallisten pakettilähteiden laatu ja päivitettävyys on hyvä mutta epävirallisilla joskus surkea - yleensä niillä on joku ylläpitäjä mutta ei aina - joten epäviralliset saattavat myös lakata toimimasta varoittamatta. Ja siitähuolimatta epäviralliset tuhoavat ihmisten halun yrittää itse sillä itse ei saa aikaiseksi mitään läheskään yhtähyvää.
- Linux/BASH:in kirous onkin niiden liioiteltu monipuolisuus - epäilenpä että Linuxin viholliset lisäävät tuota monipuolisuutta sillä se johtaa siihen ettei kukaan hallitse koko BASH-orkesteria eivätkä ainakaan pysty enää opettaamaan tulevia sukupolvia.
- lohdullista on se että pienin muutoksin samat ohjeet toimivat kaikissa jakeluissa - valitettavasti kestää vuosia oppia mitä täytyy muuttaa milloinkin.
- koska linuxin suuret gurut eivät halua että linuxiin tulisi paljon viruksia niin he ilmeisesti haluavat pitää linux:in hankala-käyttöisenä muille kuin virtuooseille - ettei se viruksien tekeminen olisi pahiksille kannattavaa kun linux ei ole kovin suosittu taviksien keskuudessa.
- BASH:iin tulee harvoin BASH:in ylläpitäjien toimesta päivityksiä - ja teoria on että ne ainoastaan korjaavat jotakin mutta todellisuus on se että ne samalla muuttavat jotakin - mutta korjaukset ovat yleensä pieniä ja niitäkin taitaa tehdä vain Chet Ramey ja ilmeisesti hänkin tekee ne harkiten - elikä BASH:issa on edes jotain melko vakaata.


Halusin kuitenkin tutkia toimiiko yli vuosikymmen sitten tekemäni päätteestä ohjelmoitavan funktiolaskimen tekevä skripti ilman muutoksia täysin samoin kuin ennen - sillä skripti vaatii koneelta paljon. Kyllä se toimii.

Toiminta jotta saisit skriptin koneeseesi: kopioi seuraava käsky koneesi selaimen osoiteriville ja paina enter:
https://forum.ubuntu-fi.org/index.php?PHPSESSID=6umrp7jv7kbakkci2rok88h899&action=dlattach;topic=303.0;attach=12583
- mene tämänjälkeen koneesi kotikansion lataukset- tai download nimiseen kansioon ja näpäytä hiiren vasemmalla kansioon ilmestynyttä tiedostoa: laskija.tar.gz
ja avautuvasta valikosta näpäytä hiiren oikealla: 'pura tähän' tai extract jolloin samaan kansioon ilmestyy skripti:laske (se on skripti sillä päätettä .sh ei toiminta kaipaa)
- näpäytä sitä hiiren oikealla ja avautuvasta valikosta näpäytä: copy
- avaa pääte ja kirjoita: .  ja paina sitten yhtaikaa nappeja shift, ctrl, ja v ja sitten paina enter (ensimmäinen merkki on piste ja sen perässä on välilyönti. Joissakin bash:eissa jätetään tuo shift pois). Jos joskus myöhemminkin haluat kokeilla laskinta niin kirjoita uudestaan tuo sama . ~/laske ja paina enter.
- näennäisesti mitään ei tapahdu mutta laskenta toimii tämän jälkeen - mutta vain tässä päätteessä niinkauan kunnes tämä pääte suljetaan. Sulkemisen jälkeen laskenta-kyky on unohdettu eikä jälki-seurauksiakaan ole.
- siis pysy nyt jatkossakin tässä päätteessä sillä jos vaihdat päätettä niin matematiikka unohtuu.

4
Assembler-tyyppisiä käskyjä on tuhansia joten normaalilla tavalla niitä ei voi esittää vaan ne täytyy esittää monella merkillä, esimerkiksi: ${muuttujanimi##*joku-merkki} tai jotain muuta ihan toisenlaista merkkisotkua - merkkisotkua siksi että niitä voisi lajitella senmukaan minkätyyppistä toimintaa ne edustavat - tosin täydelliset määrittelyt ovat hävinneet historian kätköihin ja vain muutamia on saanut kaivettua takaisin esiin.
- mutta kaikissa on tuo: joku-merkki  - ja se voi olla yksittäinen merkki, merkkiryhmä, regex, matemaattinen toiminto, funktiokutsu parametreineen ... tai jokin niiden yhdistelmä ... tai jotain muuta jonka BASH tuntee.
- niin kauan kuin yksinomaan assembler-tyyppisiä käskyjä on peräkkäin tulkataan ne kaikki samalla kerralla - ja lisäksi tulkki on järjestelmä-funktio joten se taitaa pystyä omissa tehtävissään moniajoon.
- assembler-tyyppiset käskyt toimivat myös matriisien kanssa - ja niillä voi määritellä käsittelyyn jonkun tietyn jäsenen tai määrätä kaikki jäsenet käytäväksi läpi
- regex:illä voi käsittelyyn määrätä matriisista halutun osajoukon - siis esimerkiksi jäsenet väliltä 4-7 tai kun arvossa on jokin määritelty sana (elikä vain matriisien suhteen toimiva 'super grep')

- joten assembler-tyyppiset käskyt ovat se keino jolla C-kieli alistetaan BASH:in palvelijaksi - kokemuksia ei vielä paljoa ole joten voi sanoa vain: ainakin jossainmäärin - mutta toisaalta on ihan mahdollista että edistyneemmästäkin matematiikasta saa nopeaa. Muuten aikanaan kun joku tosi isokenkäinen huomasi assembler-tyyppisten kyvyt riensi hän valmis-ohjelmien avuksi etteivät ne ihan reensijalle olisi jääneet ja laski sumuverhon 'Parameter Expansioitten' ylle.

On vain yksi paikka mistä assembler-tyyppisiä käskyjä löytää esimerkki-muotoisina ja kunnollisten selitysten kera: kansainvälisiltä foorumeilta vanhojen koodareiden kauan sitten kirjoittamista vastauksista toisten esittämiin kysymyksiin - silloin kauan sitten internetissä puhuivat vain totiset torvensoittajat ja kaikkeen saattoi luottaa - niitä viestejä kun lukee lukemattoman monia niin assembler-tyyppisten käskyjen muutkin hyödyt alkavat selvitä: niiden nopeus, vakaus, se että niitä voi ketjuttaa kuinka monta tahansa nopeuden paljoakaan laskematta eikä sitä että ketjuttamalla vain muutamia assembler-tyypisiä käskyjä saa aikaan uskomattoman monimutkaisia toimintoja - jotka edelleen ovat nopeita.

Mutta noiden esimerkkien löytymiselle on yksi suuri hidaste: oikeita hakusanoja - esimerkiksi googleen - on hyvin vaikea määritellä - oikeat löytyvät usein vasta lukemattomien harha-iskujen jälkeen. Toisaalta sellaista aihepiiriä ei ole jota joku ei olisi ratkaissut - elikä: etsi niin varmasti löydät jos jaksat yrittää. Mutta joudut kyllä silloin-tällöin kantamaan myös oman kortesi kekoon - joten jaa keräämiäsi tietoja jotta jaksaisit jatkaa.
- kuinkahan tekoäly löytää kun oppii määrittelemään 'Parameter Expansion' yleisiä piirteitä?

Mutta ilmeisesti noiden vastauksien olemassa-olo ei ole ollut jonkun mieleen sillä nuo viestit on pyritty häivyttämään pois - ja koska netistä on puoli-mahdotonta poistaa toisten kirjoituksia niin ne on haudattu lukemattomien sellaisten vastausten alle joissa on vain tavanomaisia ratkaisuja. Koska niin tapahtuu poikkeuksetta niin voiko kyseessä olla ihmisten normaali toiminta sillä assembler-tyyppinen  ei ole koskaan kysymyksen monien vastauksien loppu- eikä alkupuolellakaan vaan keskellä josta se on varmasti hidas löydettävä?

Jos jaksaa kerätä noita assembler-tyyppisiä käskyjä niin lopulta saa koottua niitä niin paljon ettei niin suurta kokonaisuutta hallitse ukko-uotinenkaan - joten ratkaisuksi voi koota niistä järjestettyjä joukkoja yhteen luntti-lappuun jota sitten voi selata editorissa. Ja kutsua niitä assembler-tyyppisiksi käskyiksi.

---

Toinen tapa esittää äsköinen asia: koska BASH toimii tulkatun kielen hitaudella niin saavuttaakseen nopeuden se pistääkin käännetyn ja moni-ajoon kykenevän ja siten nopean C-kielen tekemään työn. Vanhat virtuoosit - ne 50 vuoden takaiset - osasivat suorittaa asiat noin. Jostain syystä hekään eivät kertoneet saavutuksestaan kunnolla - esimerkiksi äsköisillä sanoilla. Eivätkö he tajunneet mitä olivat saaneet aikaiseksi? Vai älytettiinkö heitäkin - siis uskoteltiin ettei semmoista kykyä saa hyödyntää?

Nykyään RUST-ohjelmointikieli on tunkemassa Linuxiin. Sillä on tämä sama kyky ja Pythonilaiset ovat kitkeriä.

---

BASH:ia on siis vahingoitettu paljon pahemmin kuin tähänmennessä on varmistettu toimivilla skripteillä: se BASH josta normaalisti puhutaan muodostaa prosentin murto-osan siitä mikä BASH:issa toimii moitteetta: joukko-opit, bitti-operaatiot, bit-wise operaatiot ja monet muut. Mutta  koska on esitetty ettei BASH:in oma desimaali-matematiikka toimi niin kaikkea tuota käytetäm erittäin vähän. Mutta koska noiden joukkojen jäsenet toimivat hyvin assembler-tyyppisissä käskyissä jotka lisäksi mahdollistavat nopean desimaali-matematiikan niin sehän johtaa mullistavasti parempaan BASH:iin - ihan toinen asia on onko BASH:ista sittenkään enää mihinkään koska se on päästetty rappeutumaan jo vuosikymmeniä. Ja vielä epä-selvempää on kuinka aikaavievää on opetella tuota uutta BASH:ia - tai ensinhän sitä hyödyntämään täytyisi tehdä monia skriptejä esimerkeiksi - sillä täysin varmasti se on joillekuille niin kammottava asia että he tappelevat vastaan puukoin ja puntarein.

***

BASH-raamattu eli 'man bash' ei käsittele ollenkaan käsitettä nimiparametri (=namedparameter - tai millälailla se haluaankin kirjoittaa). Mutta tosi-suuret skriptit tarvitsevat niitä sillä funktiokutsussa voi arvoparametreja käytettäessä olla vain yksi tekstijono ja senkin täytyy olla viimeisenä - mutta nimiparametreilla tämmöistä rajoitusta ei ole. Mutta BASH haluttiin rajoittaa toimimaan vain pienissä skripteissä joten ei kerrottu että toimivathan ne nimiparametritkin BASH:issa. Mutta sen nimiparametrien käsittelemättä jättäminen tekee sen että luullaan etteivät nimiparametrit toimi. 

Kyllä nimiparametrienkin toiminnoista on kerrottu ihan samassa BASH-raamatussa kuin kaikesta muustakin mutta sen osat on ripoteltu sinnetänne - eihän sitä tosin voi vannoa että BASH-raamatun tekijät olisivat tajuneet että heidä kuvaamansa toiminnot muodostavat yhdessä nimiparametrin mutta olen varma että ovat tienneet.

Teoriassa nimiparametritkin ovat yksinkertaisia koska konekin ne käsittää - mutta se käsittää ne vain kun esitystapa on sille sopiva - ja ihminenkin käsittää ihan yhtähyvin jos asia esitetään hänelle sopivalla tavalla - ja koneen ja ihmisen tavat ovat ihan erilaisia. Nyt voi vain yrittää tehdä esimerkkejä ja koettaa kuvata miten BASH:in nimiparametrit toimivat.
 
Kyse on kahdesta osasta:
1. käsky: set. Käsky set on tarkoitettu arvoparametrien muodostamiseen muuttujan arvoista ja käsky toimii aivan samallatavalla sekä pää-ohjelmassa että funktiossa - siis se tekee aivan nuo samat $1, $2, $3 .... $n parametrit kuin arvoparametritkin ovat - ja näinhän BASH-raamatussa sanotaankin.
2. nimestä set tekee parametrin $1 joka tulostettuna on sama nimi kuin ennenkin. Mutta funktiossa oltaessa siihen tulleiden parametrien arvot voi tulostaa käskyllä: ${!parametrin numero} ja jos set otetaankin siitä niin saadaankin arvoparametrien joukko ja senjälkeen voidaan toimia täysin samallatavalla kuin olisi alunperinkin toimitettu funktioon arvoparametrit - elikä jo tehdyt skriptit toimivat samallatavoin kuin ennenkin vaikka niille toimitetaankin tämänjälkeen muuttujista vain nimet.

Tai asia voitaisiin esittää näinkin: myös BASH pitää kirjaa muuttujistaan ja antaa kirjanpitonsa kaikille luettavaksi. Kun pääohjelmassa on määritelty:
apu1="kaliberi:7.62 nopeus:2km/t yö-aikaan" niin tulkki tekee siitä muuttuja-taulukkoon rivin: declare -- apu1="kaliberi:7.62 nopeus:2km/t yö-aikaan". Tai:
apu2=77                                     niin tulkki tekee siitä muuttuja-taulukkoon rivin: declare -- apu2="77" 
- matriisista tulkki tekee hieman toisenlaisen rivin joten ei sotketa esitystä matriiseilla.
Kun annetaan funktio-kutsu: 
Koodia: [Valitse]
function arvoparametrien_muodostaminen_funktioon_passatusta_muuttujan_nimestä () { apu=$1; set -- "${!1}"; echo muuttujan nimeltä:$apu arvot ovat: $@  ;}
apu1="kaliberi:7.62 nopeus:2km/t yö-aikaan"; apu2=77
arvoparametrien_muodostaminen_funktioon_passatusta_muuttujan_nimestä apu1 apu2 ja sitten seuravat loput parametrit jos niitä on. # siis kutsussa on apu eikä $apu
niin kutsutussa funktiossa käsky: set "${!1}" neuvoo tulkkia hakemaan muuttujien kuvauksista rivin jonka alussa lukee teksti: 'declare -- apu1=' ja tulostamaan siitä eteenpäin  - joten siitä tulee: kaliberi:7.62 nopeus:2km/t yö-aikaan. Minut kai hirtetään jos sanon että tämä tehdään osoitin-laskentana.
- "${!1}":ssä tuo 1 viittaa ensimmäiseen parametriin; sitä muuttamalla voit tulostaa minkähyvänsa parametrin arvot - joten #${!1} tulostaa:kaliberi:7.62 nopeus:2km/t yö-aikaan - ja "${!2}" tulostaa:77. Onhan tämä sotkuisempaa kuin muissa kielissä varsinkin jos nimi-parametreja on useampia mutta toiminta on silloinkin nopeaa. Muuten parametrin $1 arvo muuttuu set-käskyssä joten se kannattaa kopioida johonkin apu-muuttujaan ihan aluksi. 
- samassa kutsussa saa olla sekaisin vaikka kuinkamonia nimi- ja arvoparametreja eikä sillä ole väliä missä järjestyksesä ne ovat. Arvoparametrin ensimmäinen merkki on $ ja nimiparametrin ensimmäinen merkki on yleensä aakkonen.
- set:in kytkimetkin kuvataan BASH-raamatussa ihan hyvin. Muuten tuo set:in perässä oleva -- on ilmoitus tulkille että onpa kytkimiä ollut tai ei niin jokatapauksessa tämänjälkeen niitä ei enää tule - joten seuraavan luettavan edessä mahdollisesti oleva miinusmerkki on tosiaan miinusmerkki eikä siis kyse ole uudesta kytkimestä.
- ei tätä tapaa yleensä kannata käyttää vaan sitä aikaisemmin esitettyä joka hyväksyy matriisitkin - mutta esitin tämän sillä tämä on yksinkertaisempi.

---

se aikaisemmin esitetty tapa joka joka tuntee kaikentyyppisistä muuttujista ihan kaiken ja toimii silti nopeasti on sekin  BASH-raamatun tiedoista kasattu mutta vielä useammista kohdista. Sitä kannattaa käyttää ja mutta siitä täytyy tehdä funktio sillä ei tällainen pitkä litania muistissa pysy. Samanlaisia pitkiä funktioita on todella paljon joten 'kirjastikielto' on todella pahantahtoinen teko ja tarkoitettu romuttamaan kieli. Mutta tähän tehtävään sovellettuna tuo parempi tapa olisi:
Koodia: [Valitse]
function arvoparametrien_muodostaminen_funktioon_passatusta_muuttujan_nimestä () { apu2=$(declare -p $1); declare ${apu2:8:2} apu=${apu2#*=}; echo muuttujan nimeltä:$1 arvot ovat: ${apu[@]}  ;}
apu1="kaliberi:7.62 nopeus:2km/t yö-aikaan"; apu2=77
arvoparametrien_muodostaminen_funktioon_passatusta_muuttujan_nimestä apu1 apu2 ja sitten seuravat loput parametrit jos niitä on. # siis kutsussa on apu eikä $apu
- ainoastaan nimiparametrit voi palauttaa. BASH:in ei tosin tarvitse palauttaa mitään mutta jos kuitenkin halutaan tehdä parametrien palauttamista vastaava toiminto annetaan BASH:issa funktion lopussa käsky: read $1<<< $apu. Tässäkin ykkösen paikalla on palautettavan parametrin numero.

- BASH:issa ei tosiaan ole automatiikkaa juuri mihinkään vaan kaikki on hoidettava itse - puhe opetuskielestä on siis ihan vakavaa sillä tämä BASH-toteutus kertoo kuinka kaikissa kielissä asiat tehdään siellä esiripun takana - toiminnan nopeus ei paljoakaan kärsi mutta monimutkaisen tuntuistahan tämä on.

5
Sain lopulta kerättyä tarpeeksi tietoa sen selvittämiseksi miksi BASH on telottu vaivaiseksi. Ei voi varmuudella sanoa että BASH on telottu tahallisesti mutta siltä se vaikutti. Tottamaar siihen voi olla ihan kunnon syytkin mutta miksei niistä puhuta selvin sanoin?

BASH:ista on tehty surkimus riistämällä siltä sen parhaat työkalut. Silloin kauan sitten varmasti tiedettiin mihin BASH kykenisi mikäli olisi tarvetta sen kykyjä täysin käyttää. Miksi noita kykyjä ei yritettykään ottaa käyttöön vaan päinvastoin BASH:ilta vietiin sen parhaat työkalut? Haluttiinko BASH poistaa markkinoilta koska sen ulkoasusta ei pidetty?

Asian tutkiminen oli vaikeaa sillä jos toimii vastoin yleisesti hyväksyttyä käsitystä ei kukaan halua uskoa sen olevan totta vaan väittää vastaan ikuisesti - siis nimenomaan 'ei halua uskoa' eikä sillä ole mitään merkitystä onko se totta vaiko ei. Kuljet siis hullun kirjoissa niin kauan kunnes vasta monen yrityksen jälkeen löydät oikeat sanat jotta edes joku uskoo - ja senjälkeen hitaasti muutkin. Mutta jo ensimmäisessä yrityksessä laitat maineesi ja itse-arvostuksesikin peliin - eikä niin kukaan järjissään oleva tee sillä jokainenhan hölmöilee joskus ja huomaa jatkossa olleensa väärässä. Mutta on yksi asia jota kukaan ei voi vääräksi osoittaa: kaikissa tilanteissa oikein toimiva skripti. Mutta vaieta voi ja olla edes tarkistamatta - elikä vaieta kuoliaaksi.

Jokatapauksessa asia BASH:in vanhoista käskyistä iso joukko on assembler-tyyppisiä. Ne tekevät jonkun pikkuhomman mutta sen ne tekevät todella nopeasti ja hyvin - ja aikaansaamatta minkäänlaista sotkua. Näitä assembler-tyyppisiä käskyjä voi laittaa peräkkäin vaikka kuinkamonta toiminnan hidastuessa sentakia vain vähän - ja vaikka sotkut ovatkin aina kasaantuvia niin eivätpä nollat miksikään kasaannu joten lopussakaan ei ole sotkua. Mutta siitä kootusta käskystä elikä funktiosta tulee lopulta nopea ja monipuolinen. Mikäli yksinomaan assembler-tyyppisiä käytettäisiin olisi toiminta 'kymmenenkertaa nopeampaa' kuin muuten eikä enää sanottaisi mistään: BASH ei osaa.... Vielä merkittävämpää on se että assembler-tyyppiset käskyt tekevät kummallistenkin toimintojen koodaamisesta mahdollista - teki mieli sanoa helppoa mutta ei, kyllä siinä pähkäillä saa - mutta se varmuus hommassa kyllä on että asiaan on montakin ratkaisua.

Tosin koodia tulee niin paljon että se paisuttaa skriptit joskus muodottomiksi - ja se tekee muun skriptin toiminnan ymmärtämisen vaikeaksi. Tämäntakia muissa kielissä funktiot laitetaan kirjastoihin ja funktiota tarvittaessa viitataan kirjastoon. Teoriassa BASH:issakin pitäisi tehdä näin - mutta koska BASH:in ei haluta toimivan hyvin ja koska kirjastot kuuluvat BASH:in perusteisiin eikä niiden toimintaa voi estää poistettiin jo toimiva kirjasto-osoitin jotta funktioilla ei olisi sijoituspaikkaa vaan ne olisi pakko kirjoittaa skriptiin - lisäksi käyttäjät käsittivät kirjasto-osoitteen poistamisen merkitsevän sitä etteivät kirjastot enää toimi vaikka tosiasiassa ne toimivat ihan hyvin. Netissäkin on kymmenkunta julkista kirjastoa jotka tosin ovat surkastuneet mutta kyllä ne toimivat.

---

Aikoinaan puhuin niin että BASH on telottu jotta valmisohjelmat voisivat esittää erinomaisuutensa. Mutta en silloin ihan itsekään uskonut siihen ihan tosissani, Mutta nyt se on selvää: valmisohjelmista ainkin osa jää assembler-tyyppisille kuin jämsän ukko taivaasta. Niin nopeudessa kuin muussakin. Tuolla myöhemmin on koodia siitä.

---

Assembler-tyyppisten käskyjen 'unohtamisen' pahin seuraus oli kuitenkin vakaan toiminnan menettäminen: esimerkiksi BASH:in 'normaaleilla' käskyillä on ongelmia jakopisteen kanssa - asembler-tyyppisillä käskyillä tätä ongelmaa ei ole. Selvityksenä mitä jakopisteellä tässä tarkoitetaan on parasta antaa siitä esimerkit:
Koodia: [Valitse]
echo 1234-5678 | cut -d- -f1    # jakopiste käskyllä: cut . Jakopiste on tuo -d:n perässä oleva - merkki.
apu=1234-5678; echo ${apu%-*}   # sama jakopiste assembler-tyyppisenä

Vakauden häviäminen on seurausta siitä että 'normaaleilla' käskyillä jakopiste muodostuu aina vain yhdestä merkistä mutta assembler-tyyppiset kelpuuttavat jakopisteeksi joko yhden merkin, merkkiryhmän,'useamman merkkiryhmän', regex:än ... - kaiketi vain mielikuvitus on rajana siinä mikä kelpaa. 

---

Tuosta 'useamman merkkiryhmän' toiminnasta täytyy antaa esimerkki.
Koodia: [Valitse]
apu=kattokassinen; [[ ${apu#*kat} != $apu ]] && echo ${apu#*to}
tulostuu: kassinen. Siis tulostetaan tekstistä merkkiryhmän to jälkeinen tekstinosa mutta vain mikäli tekstissä on jossain merkkiryhmä kat

Funktio-muotoinen versio tapauksesta jossa sen löydettävän täytyy olla etsittävän edessä - skriptin tarkoitus on myös kertoa että asiasta voi tehdä funktionkin.
Koodia: [Valitse]
function kummajainen () { apu2=${3%$1*}$1; [[ ${apu2#*$2} != $apu2 ]] && echo ${3%$2*} ;}; kummajainen to ka kattokassinen
kutsun selitys: kumajainen  minkä-jälkeinen-tulostetaaan   mitä-täytyy-olla-edessä   tekstijono-johon-toiminta-kohdistuu

---

Myös tuo regex kaipaa selvennystä -> regex on kuvaus siitä kuinka jonkun joukon jäsenet muodostetaan, esimerkiksi
[0-9][0-9]?[0-9][0-9]?[0-9][0-9] on yksinkertainen päivämäärää kuvaava regex - siinä välimerkin paikalla oleva ? tarkoittaa että silläkohtaa voi olla mikätahansa yksi merkki, myös välilyönti kelpaa. Eikä merkitse mitään mikä on päivä- kuukausi- ja vuosinumeroiden järjestys - joten käskypari:
Koodia: [Valitse]
apu="syntymäpäiväni on 29-02-00 jottas tiedätte"; echo ${apu#*[0-9][0-9]?[0-9][0-9]?[0-9][0-9]}
tulostaa sen mitä on päivämäärän perässä elikä: jottas tiedätte. Riippumatta siitä mitkä päivämäärän numerot ovat, mikä on päiväyksessä välimerkkinä ja mitkä ovat kansalliset merkintätavat joilla päivämäärä on esitetty.

Jos halutaan tulostaa ainoastaan tuo pävämäärä tulee skriptistä seuraavanlainen:
Koodia: [Valitse]
time { apu="syntymäpäiväni on 29-02-00 jottas tiedätte"; apu2=${apu//[0-9][0-9]?[0-9][0-9]?[0-9][0-9]*}; echo ${apu:${#apu2}:8} ;}
- time-käskyn ajoittama ryhmä täytyy ympäröidä aalto-suluilla jotta time-käsky mittaisi koko ryhmän kuluttaman ajan.

funktiomuotoon kirjoitettuna päiväyksen tulostamien:
Koodia: [Valitse]
function tulosta_päiväys () { apu=$1; apu1=${apu#*[0-9][0-9]?[0-9][0-9]?[0-9][0-9]}; [[ $2 ]] && { echo $((${#apu1}+1)); return ;}; echo ${apu:$((${#apu1}+1)):9} ;}
# jompikumpi kutsuista: 
tulosta_päiväys "syntymäpäiväni on 29-02-00 jottas tiedätte"   -> tulostetaan annetussa tekstijonossa oleva päiväys; tai
tulosta_päiväys "syntymäpäiväni on 29-02-00 jottas tiedätte" 0 -> tulostaa montako merkkiä on päiväyksen alkuun annetussa tekstijonossa
- tämä on tekstijonon grep sillä tiedostoille tämä ei sovellu tämmöisenään.

---

Assembler-tyyppisillä kaikenlaisten ihmeellisyyksien tekeminen on helppoa: esimerkiksi BASH:in normaalit haku-funktiot toimivat greedy-tyyppisesti elikä tulostavat mahdollisimman suuren haettavan ja tämä ei yleensä ole tarkoitus vaan lazy-tyyppisesti elikä etsittävästä pitäisikin tulostaa joku sen pienistä palasista - tähän tyyliin:
Koodia: [Valitse]
apu=kkkyjjjjhyffyfffyz; echo $apu | grep -o 'y.*y'
joka tulostaa: kyjjjjhyffyfffy kestäen noin 3ms - mutta todennaköisesti haluttaisiinkin tulostaa joku y-merkkien välisistä pikkupalasista. Grepin extended-versiolla tähän kelpaava lazy:kin toimii kun regex:ää muuttaa - mutta se toimii vielä hitaammin ja pikkuisen epävarmakin se on. Sensijaan ketjutettu assembler-tyyppinen haku kestää alle 0.5ms ja on toimintavarma.
- assembler-tyyppisillä käskyillä nuo palaset ovat:
Koodia: [Valitse]
apu=kkkyjjjjhyffyfffyz; apu=${apu%y*}; echo ${apu##*y}     # tulostaa fff
apu=kkkyjjjjhyffyfffyz; apu=${apu%y*y*}; echo ${apu##*y}   # tulostaa ff
apu=kkkyjjjjhyffyfffyz; apu=${apu%y*y*y*}; echo ${apu##*y} # tulostaa jjjh
- toimii loopillakin elikä siinä ilmoitetan vain monesko palanen lopusta laskettuna - tai pikkumuutosten jälkeen alusta laskettuna.
- toinen mielenkiintoinen 'lazy search' haku-menetelmä:
Koodia: [Valitse]
apu=kkkzixjjjjhzixffzixfffzixzapu; apu=($(echo a${apu//zix/ })); echo ${apu[1]}}

---

Siis assembler-tyyppinen käsky muokkaa joko yksittäistä tekstijonoa tai matriisin yhtä- tai jokaista jäsentä erittäin nopeasti ja valikoivasti. Matriisin käsittelyyn tarvittavat loopit ovat noissa käskyissä sisäänrakennettuja - ja ne etsivät rajansa itse sillä matriisin nimihän tunnetaan ja rajathan löytyvät silloin kirjapidosta - joten looppi on nopea koska se on käännettyä C-kieltä eikä tulkattavaa BASH:ia. 

Esimerkiksi tiedostosta tehdyn matriisin tulostus muuttaen matriisin kaikilla riveillä joku ilmaisu vaikka mimmoiseksi lauseeksi:
Koodia: [Valitse]
< /boot/grub/grub.cfg readarray array; echo "${array[@]//### BEGIN/hopsan: loopin alku}"
- pelkkä tulostaminen ei ole vaarallista. Tuota tiedostoa on mukava käyttää esimerkeissä koska se on lähes samanlaisena jokaisessa Ubuntu-koneessa.
- kestää noin 6 ms elikä 'satoja kertoja' nopempaa kuin normaalisti ja melkein  yhtä nopeaa kuin sed:illä.
- käsky:
Koodia: [Valitse]
exec < /boot/grub/grub.cfg; apu=$(cat); echo "${apu[@]//### BEGIN/hopsan: loopin alku}" > koe 
siitä kotikansioon tiedoston nimeltä koe.

Mutta täytyy lisätä ettei tulkkaava kieli voi kovin nopea olla. Vaikka esitetyllä tavalla tiedoston-käsittely nopeutuukin 'satoja kertoja' niin eihän se sittenkään kovin nopeaa ole.

6
Laitealue / Vs: Power ja Economy -ytimien hyödyllisyys
« : 05.11.24 - klo:10.14 »
Rankka käyttäminenhän sen vasta varmasti kertoo, mutta teoria on tällainen:

Tulkkaava kieli tosiaan taitaa vain hidastua jos määrättäisiin mitä ydintä milloinkin käytetään. Mutta kääntävissä kielessä kuten C ainoastaan kääntäminen hidastuu mutta käyttö nopeutuu - ja tehon säästö on melkoinen.

7
Nanosekunnin tarkkuudella toimiva ajoitus on tilastollinen ajoitus-menetelmä. Tilastollinen ajoitus-menetelmää tarvitaan millisekuntia nopeampien ilmiöiden mittaamisessa sillä time-käsky ei pysty mittaamaan niitä ollenkaan. Mutta nano-menetelmä sopii kyllä nopeisiin kertamittauksiinkin ja pitkiin aikoihin. Tässä on tarkoitus tutkia onko nano-menetelmä luotettava - ja sen toteamiseksi tehdään piirros sillä tehdyn pohjakohinan mittauksesta.

Väite: ajoitus-menetelmä on luotettava mikäli sillä mitattujen pohjakohinaa on olevien ilmiöiden mittaustulosten jakauma on gaussiaaninen - ja nano-mentelmällä on - toki vain sinnepäin mutta ihan riittävän hyvin. Vaikka päätös tehdään katsomalla dataa on se käytännössä ihan tyydyttävä menetelmä.

---

Tällaisissa piirroksissa ollaan kiinnostuneita siitä kuinka mittaustulokset ovat jakautuneet elikä kuinka usein mitattu arvo on tietyllä alueella. Jako alueisiin tehdään seuraavasti: ensin suoritetaan lukemattoman monta mittausta ja laitetan tulokset muistiin. Mittauksen jälkeen datasta määritellään suurin ja pienin mittaustulos ja jaetaan niiden väli esimerkiksi tuhanteen osaan elikä lokeroon ja tehdään myös tuhat-jäseninen matriisi joka nollataan. Senjälkeen käydään mittaukset uudestaan läpi ja jokaisesta mittaustuloksesta katsotaan mille max-min välin lokeroon se kuuluu ja kasvatetaan vastaavaa matriisin jäsentä yhdellä. Tämä matriisi on nimeltään jakauma-matriisi.

Näin täytyy muissa kielissä tehdä ja tämä tapa on BASH:issakin esikuvana mutta BASH:issa toiminta on yksinkertaisempaa: koska datassa on nanosekunnitkin niin mitattaessa jokaisesta jäsenestä leikataan kolme viimeistä numeroa pois - silloin lokero-koko on tuhat. Kun kerätyt mittaustulokset sortataan ja kootaan saman-kokoiset mittaustulokset supistetaan yhteen ja kirjoitetaan tuloksien eteen montako sitä kokoa on löytynyt - ja  jakauma on tehty.
- sorttaustapa voi olla BASH:issa vain koska sitä on tarvittu tämänkaltaisiin tehtäviin - kovin on epä-uskottava väite että tämä erittäin erikoinen sorttaustapa toimisi koska haluttiin leikkiä ja tehdä mielettömyyksiä. Mutta kyseisiä skriptejä en ole koskaan nähnyt - missä ne ovat? Pitää kylläkin paikkansa että BASH:ista kirjoittaminen on pelkkää  nöyryytystä kokoajan - sillä vaikka tekisit jotain ihan vallankumouksellisen hyvää niin aivan varmasti joku toinen pistää paremmaksi - ehkä tämäntakia yksikään järjissään oleva ei esitä skriptejään muuten kuin kysyessään neuvoa.
- jokatapauksessa BASH:issa jakauma syntyy kertaluokkia nopeammin kuin yleensä sillä sorttaus tapahtuu sen C-kielisessä rutiinissa melkein yhtä nopeasti kuin muutenkin vaikka samalla syntyy jakauma.

Sitten alkaa kokeilu kuinka niitä tuloksia käsitellään - kannattaa kokeilla sillä kokeileminen on nopeaa ja vasta loputuloksesta näkyy onko se tyydyttävä - siis samaa dataa käsitellään muuttaen jokakerta jotain ja tulos piirretään kunnes lopputulos tyydyttää.

---

Nanosekunti-menetelmä kykenee ilmoittamaan toiminnoissa kuluneen ajan mikrosekunin tarkkuudella - siis tapahtumissa 1 mikrosekunnista 1:een millisekuntiin se on ainoa tapa ajoittamiseen sillä time-käsky ei anna niissä minkäänlaista aikaa - silti silläkin alueella olisi mukava tietää kuinka luotettavan ajan nano antaa. Jokatapauksessa nano mittaa todellisuudessa kuluneen ajan ja time-käsky koodatun skriptin suoritukseen kuluneen ajan joka on huomattavasti pienempi ja näyttää paremmalta niinkuin valhe yleensäkin.

Mikäli mittaus-tulosten jakauma on rajoitettu ja gaussiaaninen on mitattava moitteetonta kohinaa elikä mittaus-tuloksia ei vääristä mikään - mutta jos jakauma on vain rajoitettu on toiminta vain todennäköisesti luotettavaa - mutta mikäli mittaustuloksien jakauma on lisäksi levinnyt suurelle alueelle ei tuloksiin voi luottaa.  Mikäli mittaukset ovat kovin lähellä sitä mikä vielä pystytään mittamaan tulee mittauksien joukon olla iso ennenkuin niistä sadaan käyrä joka on moitteeton - ja silloin on vaarana että koko järjestelmä hiipii koko mittauksen ajan johonkin suuntaan ja lopputulos leviää suurelle alalle - joten jos kuitenkin saadaan gaussiaaninen käyrä niin samalla on selvinnyt sekin ettei järjestelmä ryömi.

Tässä mittauksessa mitataan BASH:in nopeimman toiminnon suoritusaikaa - siis yritetään mitata omaa minimiä joka normaalisti on melkein mahdotonta muttaa BASH:ille se on läpihuuto juttu. BASH:in nopein komento on : elikä kaksoispiste - assemblerissa vastaava käsky on NOP elikä: teeskentele että teet jotakin vaikka todellisuudessa et tee mitään. Täysi mittaus kestää noin neljä tuntia - mutta jo vartti-tunnissa saa aikahyvän käyrän ja kun mittaa monta kertaa niin lopputulos on jokseenkin sama.

Piirroksen tuloksista ei selviä todelliset ajat vaan käyrä on suhteellinen - mutta koska käyrän muoto on oikea niin ei niitä tarkkoja aikoja tarvitakaan. Käyrästä muuten selviää sekin että vieläkin lyhyempiä aikoja saisi mitattua jos hyväksytään se että aikaa kuluu huomattavasti lisää.  Mittaus skripti on seuraavanlainen:
Koodia: [Valitse]
function nano () { date +%s%N > alkuhetki; $@ ; date +%s%N > loppuhetki; sleep 0.01; echo $(($(cat loppuhetki) - $(cat alkuhetki))) >> ~/nano/data ;}

kertoja=75000; rm -f ~/nano/data; mkdir -p ~/nano; touch ~/nano/data ; time for (( n=1; n<=$kertoja; n++ )); do nano : ; done

# kokeiluihin leikataan vain seuraavat lauseet ja muokataan niitä - aikaa säästyy ja saa tutkia samaa tilannetta jokaisella kerralla
rm -f ~/nano/data2; rm -f ~/nano/data3; touch ~/nano/data2; touch ~/nano/data3; readarray -t apu < ~/nano/data; for (( n=0; n<${#apu[@]}; n++ )); do echo $((${apu[$n]}/2000)) >> ~/nano/data2; done; sort -n ~/nano/data2 | uniq -c >~/nano/data3
# mutta tiedostossa  ~/nano/data3 ovat y ja x väärässä järjestyksessä joten niiden järjestys täytyy vaihtaa:
while read -r line; do set $line; echo $2 $1; done < ~/nano/data3 > ~/nano/data4 # siis saman lauseen sekä sisäänmeno että ulostulo voidaan uudelleensuunnata yhtaikaa

# tiedostossa ~/nano/data4 on paljon turhia rivejä joten hyväksytään arvoja vain merkitykselliseltä alueelta jotta käyrästä saisi paremmin selvää
cp <(sed -n '160,460 p' ~/nano/data4) ~/nano/data5

gnuplot -p -e 'set terminal gif;  set output "~/nano/jakauma_suppea.gif";set xlabel "suhteellinen aika"; set ylabel "aikojen jakauma"; plot "~/nano/data5"'
gnuplot -p -e 'set terminal gif;  set output "~/nano/jakauma_laaja.gif";set xlabel "suhteellinen aika"; set ylabel "aikojen jakauma"; plot "~/nano/data4"' 

- käyrät ovat tiedostoissa: ~/nano/data4 ja ~/nano/data5

----

- mittasin nano:lla keskiarvoja lyhyistä sleep-käskyistä - nuo lyhyet ajat heittelee muuten liikaa jos niitä ei keskiarvoista - siis lyhyetkin sleep:it onnistuvat ja nanokin näyttää mikroskunnit - ovatko ne oikein ei kukaan voi arvellakaan - mutta ainakin ne ovat jotakin sinnepäin ja lisäksi toistettavissa varsinkin otettaessa keskiarvoa kauan - Linux se on joka tuloksia runtelee, ei BASH. 

asetusarvo sekunneissa      nanon tulos    time-käskyn tulos
             1.234567       1.236231       1.237
             .1234567       .125084        0.126
             .01234567      .013748        0.015
             .001234567     .002459        0.004   siis nano voi olla 114 mikro-sekuntia poskellaan ja time-käsky 4000 elikä 35 kertaisesti
             .0001234567    .001045        0.004
             .00001234567   .000939        0.004 





8
Sitten desimaaliluvuista muodostetun matriisin jåsenien summaus tyyliin: 'ynnää kauppalaskun summat'- mutta sen voi koodata toimimaan ihan niinkuin haluaa. Tämäntyyppinen toiminta edellyttää parametrien siirtämistä nimiparametreina. BASH ei osaa palauttaa parametreja sillä se olisi turhaa - sillä ne palautuvat toiminnan aikana auomaattisesti mikäli tarpeen on.

- nuo lauseet funktion add_decimal_matrix alussa: apu=$(declare -p $1); declare ${apu:8:2} data=${apu#*=} kloonaavat funktioon tulleen $i nimisen muuttujan annetulle nimelle
- teoriassa kloonaamiseeen on käsky: declare -p nimi=$1 mutta se tuntuu olevan liian buginen tähän.
Koodia: [Valitse]
function add_decimal_matrix () { apu=$(declare -p $1); declare ${apu:8:2} data=${apu#*=}; savedata=(${data[@]}); apu=${#data[@]}; for (( n=0; n<=$apu; n++ )); do data[$n]=${data[$n]#*.}; data[$n]=${data[$n]}'0000000000000000000'; data[$n]=${data[$n]:0:15}; done; apu=$(($(echo ${data[@]} | tr ' ' '+'))); desimaalit=$(echo "${apu: -15}"); ylivuoto=${apu:0: -15}; kokonaiset=$(($(echo ${savedata[@]%.*} | tr ' ' '+')+$ylivuoto)); echo 'summa: '$kokonaiset'.'$desimaalit ;}

# esimerkki kutsu:
unset data; for ((n=1;n<=200;n++)); do data[$n]=$RANDOM$SRANDOM.$RANDOM$SRANDOM; done; clear; echo 'seuraava summattava matriisi vaihtuu jokaisella ajokerralla ja tällä kerralla se on:   '${data[@]}; echo; time add_decimal_matrix data; echo "bc:n antama varmasti oikea tulos johon voi verrata:"; echo -n '       ';bc -l<<<"$(echo ${data[@]} | tr ' ' '+')"

- tuo käsky: unset johtuu siitä että muuten määriteltäessä uudestaan edelliset määrittelyt häiriköisivät.
- matriisin koolla ei ole väliä muuten kuin että se hidastaa - ainakin 25000 onnistuu ja aikaa kuluu silloin sekunti.

9
BASH ei ole sellainen surkimus miksi se kuvataan - hidas se on kyllä mutta sen hitautta liioitellaan aina. Mutta toisaalta BASH:issa voi tehdä mitävaan - vaikka toisin väitetään - tosin useimmat edistynemmät toiminnot ovat vieläkin hitaampia ja kömpelömpiä mutta vastikkeeksi ne voi toteuttaa lukemattomilla täysin erilaisilla tavoilla joista jokaisella on omat ominaisuutensa - hyviä ja huonoja - joten ainakin oppii kritisoimaan omia tekemisiään.

En yritä edes ymmärtää miksi ja miten meille kaikille on pätevästi osoitettu että BASH:in matriisioperaatiot ovat kelvottomia sillä todellisuudessa ne ovat sentään käyttökelpoiset. Minäkin luulin aikoinaan BASH:in matriisioperaatioita käyttökelvottomiksi mutta tehdessäni funktioita matrisioperaatioita varten huomasin BASH:in monipuolisuuden matriiseissakin - vähättelijöistä ihmettelen kuinka kaikki voivat silmät sinisinä sanoa ettei BASH parempia menetelmiä edes tunne kun väittäjistä joku on itse ne toteuttanut?

Näin ensialkuun tein skriptin matriisin muodostamiseen : matriisin nimi on koematriisi, sen riviluku on 200 ja sarakeluku 26 - tulostuksesta sen rakenne selviää parhaiten:
Koodia: [Valitse]
function koematriisin_kasaus () { unset koematriisi; for ((n=1;n<=200;n++)); do koematriisi[$n]=$(echo {a..z} | sed "s/[a-z]/&$n/g" ); done; echo tämmöinen matriisista tuli:; echo; printf "%s\n" "${koematriisi[@]}" | column -t ;}; koematriisin_kasaus
- kun matriisi on muodostettu pysyy se määriteltynä niin kauan kuin päätettä ei sammuteta.

Sitten arvon hakeminen siitä - ja koska BASH on matriisioperaatioissa todella hidas niin vastikkeeksi laitoin tarkistuksen siitä ettei matriisin rajoja ylitetä (sentakia käytetään nimiparametria):
Koodia: [Valitse]
function arvo_matriisissa () { apu=$(declare -p $1); declare ${apu:8:2} apu2=${apu#*=} # apu2 saa funktioon nimenä tulleen muuttujan tyypin ja arvot
[[ $apu =~ \[$2\] ]] || { echo matriisissa ei ole sellaista riviä; return ;}
matriisin_rivi=($(echo ${apu2[$2]})); arvo_rivilla=${matriisin_rivi[$3-1]}
[[ $arvo_rivilla ]] && echo $arvo_rivilla|| { echo matriisissa ei ole sellaista saraketta; return ;} ;}
# esimerkkikutsu:
arvo_matriisissa koematriisi 200 26 # arvo joka on koematriisin rivillä 200 sarakkeessa 26

---

Kyllä tämä BASH on nolostuttava - koematriisin tekemiseen on aivan yksinkertainenkin tapa joka ei vaadi temppuilua - ja tehdään samalla iso koematriisi, se kylläkin kestää puolisen minuuttia:
Koodia: [Valitse]
unset koematriisi; for n in {1..20000};do koematriisi[$n]=$(echo {a..z}$n) ; done;printf "%s\n" "${koematriisi[@]}"

Samoin funktion arvo_matriisissa voi kirjoittaa yksinkertaisemminkin:
Koodia: [Valitse]
function arvo_matriisissa () { apu=$(declare -p $1); declare ${apu:8:2} apu2=${apu#*=}; printf "%s\n" "${apu2[@]}" | cut -d ' ' --fields=$3 | tr '\n' ' ' | cut -d ' ' --fields=$2 ;}
- ei siitä nopeus-hyötyä tosin ole -  se on vain sama asia kerrottuna toisella tavalla.

10
Kolmiulotteisen matriisiin tulostaminen: ensiksi muodostetaan ajatuksissa kaksiulotteinen matriisi - kaksiulottteisella puolella voi käyttää 'valenimiä' sillä eiväthän ne lopputuloksessa näy - mutta valinta yksinkertaistuu. Siis tehdään senmuotoinen kaksiulotteinen matriisi kun kuuluu - esimerkiksi:
a b c
d e f
g h i

# halutaan tulostaa tämän kolmiulotteisen mariisin jäsen 3 3 3 (=rivi 3,sarake 3, alkio 3). muodostetaan ensin valenimistä oikean muotoinen matriisi:
Koodia: [Valitse]
unset matriisi; readarray matriisi<<<'a b c
d e f
g h i';  echo tämmöinen kaksiulotteisesta matriisista tuli:; echo; printf "%s\n" "${matriisi[@]}" | column -t; echo

# Sitten muodostetaan kaksiulotteisen alkioita vastaavat lukujoukot. Lukujoukoissa on yleensä kaikissa sama määrä jäseniä mutta se ei ole pakko.
 
a="1 2 4"
b="2 4 6"
c="3 6 9"
d="4 8 12"
e="5 10 15"
f="6 12 18"
g="7 14 21"
h="8 16 24"
i="9 18 27"

# haetaan oikea alkio kaksiulotteisela puolelta sen alkio 'rivi sarake':
function hae_arvo_matriisista () { # kutsu on muotoa: matriisin_nimi rivinumero sarakenumero
 apu1=$(declare -p $1); declare ${apu1:8:2} apu2=${apu1#*=}; apu=($(echo ${apu2[$(($2-1))]})); echo ${apu[@]:$(($3-1))} ;}

# mudostetaan tuossa 'oikeassa alkiossa ' olevista alkioista matriisi josta tulostetaan valittu jäsen
apu=($(hae_arvo_matriisista matriisi 3 3)); apu=($(eval echo \$"$apu")); echo ${apu[2]} # jäsen matriisi 3 3 3 = 27

---

Toiminta on samantapaista käytännön isoissa matriiseissa: esimerkiksi vuoden jokaisena päivänä mitataan lämpötilaa kerran minuutisssa ja siitä tehdään matriisi. Matriisin kaksiulotteinen puoli jakaa sen päiviksi ja niiden tunneiksi. Sitävarten muodostetaan kaksiulotteinen matriisi näin:
Koodia: [Valitse]
readarray matriisi<<<"$(for n in {1..365}; do for m in {1..24}; do echo -n $n't'$m' '; done; echo; done)";  echo tämmöinen kaksiulotteisesta matriisista tuli:; echo; printf "%s\n" "${matriisi[@]}" | column -t; echo
Sen alkiot täytetään kerran minuutissa tapahtuvilla mitauksilla - mittausarvojen väliin tulee välilyönti - ja joka tunti siirrytään täytämään sille tunnille osoitettua kaksiulotteisen matriisin jäsentä näillä lämpötilamittauksilla.

11
Tulkki päättää mitä se tekee sille syötetylle tekstijonolle. Vaikka mielestäsi olet antanut tulkille muuttujan niin tulkki tekee oman päätöksensä - kylläkin tarkkojen sääntöjen mukaan.

Muuttuja voidaan tulkita komennoksi - ja sitä komentoa voi käyttää aivan niinkuin se olisi kirjoitettu näppäimillä - ja tuolla komennolla voi olla mitkä parametrit vaan:
Esimerkiksi: a='echo onnistuuhan tämä näinkin'; $a .

Muuttuja voidaan tulkita funktiokutsuksikin. Muuttujana voi olla myös matriisi ja silloin toiminta ratkaisee monta ongelmaa - se on kasapanos sirpalekranaatti sotilaskielellä; ainoa mitä se vaatii on rajaton mielikuvitus. Ja mikäli muuttuja on peräti assosiatiivinen matriisi niin sillä voi tehdä monenmoista muutakin, koodimuunnoksen esimerkiksi.

Muuttujaan voidaan laittaa myös laskukaava. Se tarvitsee avukseen funktiota, esimerkiksi: function ratkaisija () { export BC_LINE_LENGTH=0; echo $1 | tr '[]' '()' | sed 's/x/'$2'/g' | sed 's/e/e(1)/g' | sed 's/pii/4*a(1)/g' | bc -l ;}
- sitten määritellään muuttujaan laskukaava, esimerkiksi: a=x^2+x+1  - ja ratkaistaam a:n arvo kun x on jotakin, esimerkiksi: ratkaisija $a 2
- kaavaksi voi vaihtaa mitä lystäät ja luvut voivat olla millaisia reaalilukuja vaan - pituus on rajoittamaton ja desimaalipikku voi sisäänmenossakin olla.
- tällä tyypillä voit myös kysella vakioiden arvoja:
a=e;ratkaisija  $a -> kysytään luonnon vakion e arvoa
a=pii;ratkaisija $a -> kysytään piin arvoa
a=e^pi/s[2]*l[2]; ratkaisija $a  # tuo: s[2] on sini 2-radiaania ja l on ln
a=6^5^6-6^6^6;ratkaisija $a
a=$(seq -s '*' 1 10000); ratkaisija $a # 10000 kertoma
- BASH tykkää kyttyrää kaarisuluista ja on pakko käyttää hakasulkuja.
- bc laskee radiaaneissa.
- muutenkin merkintätavat ovat toistaiseksi hieman hakusessa
- jokatapauksessa kun funktion kirjoittaa skriptin alkuun niin laskuja voi suorittaa missävaan kutsulla: ratkaisija melkein_mitä_matemaattista_haluat.

---

Anna käsky: echo 'function x () { x=$(($1)); echo $x ;}' >> ~/.bashrc   - ja boottaa kone
Senjälkeen voit kirjoittaa skripteihisi mihin vaan laskun  tyyppiä:  x 1+1
ja se kirjoittaa näytölle 2 samoinkuin asettaa muuttujan x arvoksi 2 .
- numeroiksi kelpaa kaikki numeroiksi kelvollinen ja +merkin tilalla mitä vaan BASH hyväksyy. Itseasiassa helpompaa kuin muissa kielissä sillä = merkkiä ei tarvita
- tai kirjoita funktio kerro18 sinne .basrc:hen. Senjälkeen voit kirjoittaa laskuja tyyppiä: kerro18 .00900007567899123 900.07000012345678 ja saat vastauksen:
8.1006981175007567491845709040394 joka menee myös muuttujan kerro18 arvoksi

---


Mutta tuo edellinen ei sovi laskuihin joissa voi olla desimaali-lukuja sillä jokainen desimaali-laskutyyppi vaatii oman rutiininsa eikä niiden kaikkien nimi voi olla x. Mutta tässä nimi x johtaakin kuori-funktioon joka jakaa toiminnot eri rutiineihin sen perusteella mikä matemaattinen komento kuori-funktioon tulleessa käskyssä on.
- vanhoista käskyistä muodostetut skriptit ovat niin nopeita ettei niistä muodostettu tällainen kuori-funktio juurikaan hidasta.
- kuori-funktiota on monia muitakin, esimerkiksi matematiikka-ohjelma bc on kuori-funktio todella vaikeakäyttöiselle matematiikka funktiolle dc.
- tuon x:n yleisyydestä: kun selaat minkä tekstin vaan niin siellä ei ole 'koskaan' pientä x:ää jonka kummallakin puolella on välilyönti - rivin alku toimii myös välilyöntinä.
- kaikille funktioile löytyy parempiakin versioita mutta ne ovat paljon iso-kokoisempia.

Toki nämä skriptit ovat isokokoisia mutta kun kirjoittaa ne .bashrc:hen ovat ne jokaisessa skriptissä käytettävissä hakematta niitä kirjastosta. Siitäs saatte, virtuoosit - nyt BASH on perus-laskuissa helppokäyttöisempi ja nopeampi kuin muut kielet. Tosin .bashrc:n sörkkiminen on vaarallista mutta virtuoosien piikkiinhän tämä menee.
- jos botattuaan kirjoittaa mihin tahansa skriptiin: x 1.5*1.5 niin tulos 2.25 kirjoittuu näytölle ja muuttujan: x arvosi tulee myös 2.25. Sitä x:ää ei voi vaihtaa toisen-nimiseksi muutujaksi mutta saahan x:n arvon kopioitua toiseen muuttujaan, esimerkiksi: y=$x

Mutta oikeastaan tästä ei ole kyse eikä siitäkään että jos Chet Ramey auttaisi hieman olisi BASH perus-matikassa skriptauskielten kunkku jo nyt. Mutta tulevaisuutta ei tosiaan tiedä mutta luotan siihen että silloin kauan sitten virtuoosit tekivät monenlaisia muitakin ihmeitä jotka aikanaan paljastuvat varmasti - sitä en kylläkään käsitä miksi he eivät jakaneet suurella vaivalla tehtyjä skriptejään myös muille - sillä on ehdottomasti täysin varma että toimivia skriptejä on ollut silloin pari-kolmekymmentä vuotta sitten. Samaan ihmetysten joukkoon menee se että miksi jo toimiva BASH-skriptien kääntäminen peruttiin.
Koodia: [Valitse]
function x () { apu=$1; etuluku=${apu%%[*/+-]*}; takaluku=${apu##*[*/+-]}
[[ $takaluku$etuluku =~ \. || $apu =~ \/ ]] || { echo $(($1)); return ;} # kokonaisluvut lasketaan kuten ennenkin lukuunottamatta jakolaskua
[[ $takaluku =~ \. ]] || takaluku=$takaluku'.';  [[ $etuluku =~ \. ]]  || etuluku=$etuluku'.'
[[ $apu =~ \* ]] && $(echo kerro9 $etuluku' '$takaluku)
[[ $apu =~ \/ ]] && $(echo jaa $etuluku' '$takaluku)
[[ $apu =~ \+ ]] && $(echo summaa18 $etuluku' '$takaluku)
[[ $apu =~ \- ]] && $(echo miinus18 $etuluku' '$takaluku) ;}

function kerro9 () { apu=$1; apu=${apu##*.}; apu2=$2; apu2=$apu${apu2##*.}; desi=${#apu2}; tulos=$((${1//\./}*${2//\./})); echo ${tulos:0: -$desi}.${tulos: -$desi} ;};

function summaa18 () { luku1=$1 ; [[ $luku1 =~ \. ]] || luku1=$luku1.0; desi1=${luku1##*.}; koko1=${luku1%%.*}; luku2=$2; [[ $luku2 =~ \. ]] || luku2=$luku2.0; desi2=${luku2##*.}; koko2=${luku2%%.*};  (( ${#desi1} >= ${#desi2} )) && desipituus=${#desi1} || desipituus=${#desi2} ; desi1=$desi1'000000000000000000000000';
desi2=$desi2'000000000000000000'; desi1=${desi1:0:$desipituus}; desi2=${desi2:0:$desipituus}; apu=$(($desi1+$desi2)); desisumma=${apu: -$desipituus}; ylivuoto=${apu:0: -$desipituus}; [[ $ylivuoto ]] || ylivuoto=0; echo $(($koko1+$koko2+$ylivuoto)).$desisumma ;}

function miinus18 () { luku1=$1 ; [[ $luku1 =~ . ]] && desi1=${luku1##*.} || desi1=0 ; koko1=${luku1%%.*}; luku2=$2; [[ $luku2 =~ . ]] && desi2=${luku2##*.} || desi2=0 ; koko2=${luku2%%.*}
# desimaaliosien tulee olla yhtäpitkät. Lyhyemmän perään kirjoitetaan nollia sillä ne eivät muuta desimaaliosassa arvoa.
(( ${#desi1} >= ${#desi2} )) && desipituus=${#desi1} || desipituus=${#desi2}
desi1=$desi1'000000000000000000'; desi2=$desi2'000000000000000000'
desi1=${desi1:0:$desipituus}; desi2=${desi2:0:$desipituus}
apu=$(($desi1-$desi2))
desisumma=${apu: -$desipituus}; alivuoto=0; [[ $desisumma < 0 ]] && { alivuoto=1; desisumma=$(($desisumma+1000000000000000000)) ;}; echo $(($koko1-$koko2-$alivuoto)).$desisumma ;}

function jaa () { (( ! $# )) && echo funktion ajokäsky on muotoa: jaa 1 2 . Siitä pitää tulla: .5000000000000000000000000000 && sleep 2 && return
[[ ${1//[^.]/} ]] && luku1=$1 || luku1=$1"."
[[ ${2//[^.]/} ]] && luku2=$2 || luku2=$2"."
desimaaliosa1=${luku1##*.}
desimaaliosa2=${luku2##*.}
int1=${luku1%%.*}
int2=${luku2%%.*}
[[ ${#desimaaliosa2} -gt ${#desimaaliosa1} ]] && desi=${#desimaaliosa} || desi=${#desimaaliosa1} #desimaaliosan pituus:
apu=$((${1//\./}%${2//\./}))"000000000000000000"; apu=${apu:0:18}
tulos=$((${1//\./}/${2//\./}))$(($apu/${2//\./})); echo ${tulos:0: -$desi}.${tulos: -$desi} ;}


x 9999.99999*9999.99999                           # = 99999999.8000000001
x 12345.67890123456+12345.67                 # = 24691.34890123456
x 12345.67890123456-1234.56789012345  # = 11111.11101111111
x 1111111111111111.5/1.51                          # = .735835172921265894039735099337

- kaikkien kesto-aika on noin 1 ms.

12
Aikoinaan ei annettu pienintäkään toivoa sille että kaksiulotteiset matriisit toimisivat joskus - että voisi tehdä funktion hakemaan matriisista yhden jäsenen tai asettamaan sen kun määrätään matriisin rivi ja sarake. Sellaista kaivattiin jo vuosikymmeniä sitten ja monet yrittivät sellaista tehdäkin mutta se ei onnistunut niin että sitä olisi kannattanut käyttää.

Toisaalta BASH:issa on aina ollut kaksiulotteisia matriiseja. Mutta aikaisemmin ei ole osattu kasata funktioita niiden käsittelemiseksi - se mihin kaikki ovat kompastuneet on se että kaksiuloteiset matriisi-operaatiot saa helpoiksi vain kun käyttää matriisi-operaatiota.

Kaksiulotteiset matriisit olisivat siis toimineet jollaintavoin jo kauan sitten jos vain olisi tajuttu kuinka niiden funktiot kasataan sellaisella tavalla että niiden toiminasta tulisi samanlaista kuin muillakin kielillä.

Monet käskyt kuuluvat yhtaikaa sekä vanhoihin että uusiin käskyihin joten sanotaan että näissä käytetään nopeita käskyjä. Sekä luku että kirjoitus kestääkin vain millisekunnin riippumatta paljoakaan matriisin koosta.

Tässä on funktiot sekä kirjoittamiselle että lukemiselle - tässäon vain periaata matriisin käsittelylle eikä vielä lopullinen versio. Kokeillesssa kommentoidaan luku ja käytetään kirjoitusta - tai käytetään lukuaja kommentoidaan kirjoitus:
Koodia: [Valitse]

# ensiksi tehdään koematriisi:
function matrixn_kasaus () { unset matrix; for ((n=1;n<=200;n++)); do matrix[$n]=$(echo {a..z} | sed "s/[a-z]/&$n/g" ); done; echo tämmöinen matriisista tuli:; echo; printf "%s\n" "${matrix[@]}" | column -t ;}; matrixn_kasaus

# ja sitten funktiot sekä kirjoittamiseen että lukemiseen
function kirjoita_matriisiin () {
mat=(${matrix[$1]}); riviluku=${#matrix[@]}; apu=${matrix[1]//[! ]/}; rivinpituus=${#apu} # pitäisiköhän olla: [! *] - aika näyttää
apu1=''; for (( n=0; n<$2; n++ )); do apu1=$apu1' '${mat[$n]}; done
apu2=''; for (( n=11; n<=$rivinpituus; n++ )); do apu2=$apu2' '${mat[$n]}; done
matrix[$1]=$apu1' '$3' '$apu2 ;}

function lue_matriisista () {
mat=(${matrix[$1]}); riviluku=${#matrix[@]}; apu=${matrix[1]//[! ]/}; rivinpituus=${#apu} # pitisiköhän olla: [! *]
apu1=''; for (( n=0; n<=$2; n++ )); do apu1=$apu1' '${mat[$n]}; done
read<<<${apu1##* } $3 ;} # nimi-parametrin asettaminen

# esimerkki kutsun kirjoittamiseen:
read -p 'jatkaakseesi paina return' apu; time kirjoita_matriisiin 199 10 ppp; echo tämmöinen matriisista tuli:; echo; { printf "%s\n" "${matrix[@]}" | column -t ;}
# esimerkkikutsun lukemiseen:
# read -p 'jatkaakseesi paina return' apu; time lue_matriisista 199 10 muuttuja;echo 'siinä paikassa on: '$muuttuja # muuttuja-nimi voi olla mikävaan

---

- edellä oletettiin matriisin nimeksi matrix ja niinhän ei käytännössä yleensä ole. Matriisin nimi täytyykin passata nimiparametrina ja sitähän väitetään mahdottomaksi mutta tässä sitä käytetään: tullessa kloonataan samanlainen muuttuja kuin nimen mukaan kirjanpidossa on - ja lähtiessä kloonataan se takaisin . Se kylläkin tekee sen että kutsussa täytyy antaa myös matriisin nimi.
- tosin tällä on monia sivuvakutuksia ja ne täytyykin poistaa yksi kerrallaan - kyllä nyt itselleni työmaan järjestin.
 
Koodia: [Valitse]
# ensiksi tehdään koematriisi:
function matriisin_kasaus () { unset matriisi; for ((n=1;n<=200;n++)); do matriisi[$n]=$(echo {a..z} | sed "s/[a-z]/&$n/g" ); done; echo tämmöinen matriisista tuli:; echo; printf "%s\n" "${matriisi[@]}" | column -t ;}; matriisin_kasaus

function kirjoita_matriisiin () {
[[ $4 ]] && apu1=$(declare -p $4); declare ${apu1:8:2} matrix=${apu1#*=}
mat=(${matrix[$1]}); riviluku=${#matrix[@]}; apu=${matrix[1]//[! ]/}; rivinpituus=${#apu} # pitäisiköhän olla: [! *] - aika näyttää
apu1=''; for (( n=0; n<$2; n++ )); do apu1=$apu1' '${mat[$n]}; done
apu2=''; for (( n=11; n<=$rivinpituus; n++ )); do apu2=$apu2' '${mat[$n]}; done
read<<<$apu1' '$3' '$apu2  $4[$1] ;}

function lue_matriisista () {
mat=(${matrix[$1]}); riviluku=${#matrix[@]}; apu=${matrix[1]//[! ]/}; rivinpituus=${#apu} # pitisiköhän olla: [! *]
apu1=''; for (( n=0; n<=$2; n++ )); do apu1=$apu1' '${mat[$n]}; done
read<<<${apu1##* } $3 ;} # nimi-parametrin asettaminen

# esimerkki kutsu kirjoittamiseen:
read -p 'jatkaakseesi paina return' apu; time kirjoita_matriisiin 199 10 ppp matriisi; echo tämmöinen matriisista tuli:; echo; { printf "%s\n" "${matriisi[@]}" | column -t ;}
# esimerkkikutsu lukemiseen:
# read -p 'jatkaakseesi paina return' apu; time lue_matriisista 199 10 muuttuja;echo 'siinä paikassa on: '$muuttuja # muuttuja-nimi voi olla mikävaan


13
Tekstijonon ja matriisin käsittelyyn tarvitaan omat funktiot. Kuitenkin tekstijono on matriisin jäsen nolla - selitys siihen on aivan yksinkertainen: kun matriisin indeksiä ei määrätä niin oletetaan että se on nolla. Ja vain koska tätä ei kerrota missään niin koko käsite on umpisolmussa. Sillä kaikkia muitakin matriisin jäseniä käsitellään toisin kuin koko matriisia - ei tekstijono ole minkäänlainen poikkeus. Esitetäänpä asia toisellatavalla:

BASH antaa skriptaajan tutkia kirjanpitoaan ja sieltä selviää muunmuassa kuinka minkin niminen muuttuja on määritelty. Anna kaksi käskyä ja tutkiskele tulostusta:
Koodia: [Valitse]
muuttuja="1 2 3"; declare -p muuttuja #-> tulostaa: declare -- muuttuja="1 2 3"
muuttuja=(1 2 3); declare -p muuttuja #-> tulostaa: declare -a muuttuja=([0]="1" [1]="2" [2]="3")


nyt tee kummajaiskäsky ihan vaan tutkimismielessä - tämänkaltaisissa tutkimuksissa kannattaa jokakerta avata uusi pääte sillä BASH:in roskankeruu on olematonta ja vanhat tulokset voivat muuten kummitella - mutta uudessa päätteessä voi olla varma siitä että kaikki roskat ovat hävinneet:
Koodia: [Valitse]
muuttuja=(1 2 3); muuttuja="1 2 3"; declare -p muuttuja -> tulostaa: declare -a muuttuja=([0]="1 2 3" [1]="2" [2]="3")
tulkki ei osaa suhtautua mielipuolisuuteen mutta tulostus kertoo sentään tekstijonon olevan matriisin jäsen nolla. Minkä muuten voit todeta toisinkin - avaa uusi pääte ja käske:
Koodia: [Valitse]
muuttuja="1 2 3"; echo ${muuttuja[0]} -> tulostuu: 1 2 3 #-> siis teit tekstijonon, tulostit matriisin ja silti onnistui ihan hyvin.

Kun mielestään tekee matriisin niin helposti siitä onkin tullut tekstijono eikä sitä välttämättä huomaa sillä virhe se ei ole vaan ainoastaan teko jota ei tarkoitettu - sillä matriisihan siitä tuli mutta kaikki arvot ovat jäsenessä nolla. Siis jos käsky: echo ${muuttuja[0]} tulostaa kaikki arvot niin kyseessä on tekstijono. Mutta tarkistamiseen kannattaa tehdä skripti sillä tietoja tarvitaan vähän lisääkin. Xref skriptin käytäminen on helppoa, kutsut vain: xref muuttujan_nimi. Xref ilmoittaa myös sotkuista tai jos muuttujan arvoa ei ole märätty - esimerkiksi käsky: muuttuja=(1 2 3); muuttuja="1 2 3"; xref muuttuja tulostaa tämmöistä:

muuttuja on matriisi.
arvot    : 1 2 3 2 3
osoitteet: 0 1 2
- ensimmäisen rivin kaksi viimeistä merkkiä ovat melkoisia haamuja; joillain tavoilla tulostettaessa ne näkyy ja toisilla ei.
- oikeastaan muuttuja-määrittelyn aluksi pitäisi antaa käsky: unset muutuja_nimi - silloin ei varmasti synny sotkuja - vaan enpä ole moiseen koskaan törmännyt vaikka ei käsky toimintaa hidastaisi sillä se on vain ohje kuinka pitää muutuja muodostaa.

Xref skriptin koodi:
Koodia: [Valitse]
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[@]}  | column -t # arvo ja sitä vastaava osoite kirjoitetaan aina alekkain riippumatta niiden pituuksista - joskus kylläkin vain teoriassa.
}; echo ;}

function xref () {
[[ $(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
echo # funktiossa täytyy aina tehdä jotakin - vaikka tulostaa tyhjää. Jos siinä on pelkkiä ehtoja eikä yksikään niistä toteudu niin muuten tulisi suoritusaikainen virhe
}

Käytännössä tämä vaikuttaa esimerkiksi näin kun muuttuja on joko testijono "1 2 3" tai matriisi (1 2 3):
Koodia: [Valitse]
echo ${muuttuja[@]} tulostaa sekä tekstijonon että matriisin:1 2 3
echo ${muuttuja[0]} tulostaa 1 jos kyseessä on matriisi mutta tekstijonon se tulostaa: 1 2 3
echo ${muuttuja[1]} tulostaa 2 jos kyseessä on matriisi mutta tekstijono ei tulosta mitään.
echo ${muuttuja[2]} tulostaa 3 jos kyseessä on matriisi mutta tekstijono ei tulosta mitään.

--------
 
Kokosin muutamia sellaisia käskyjä jotka toimivat matriiseilla joiden jäsenet voivat olla pitkiäkin tekstijonoja joissa voi olla välilyöntejä tai ei - ja käytännössähän useimmat matriisit ovat tällaisia.
Koodia: [Valitse]
echo ${muuttuja[1]:3:4} tulostaa matriisin toiselta riviltä alkaen merkistä 3 neljä merkkiä eteenpäin.
echo ${muuttuja[@]:3:4} tulostaa merkit 3-7 kaikilta matriisin riveiltä.
echo ${muuttuja[1]#* * * } puolestaan tulostaa toiselta riviltä kolmannen välilyönnin jälkeiset merkit rivin loppuun asti.
- välilyönnin paikalla voi olla myös sana, lueteltu merkkiryhmä (esimerkiksi[1 5] joka on 1 tai 5), regex (esimerkiksi [1-5] on kaikki numerot 1-5) ...
echo ${muuttuja[@]#* * * } puolestaan tulostaa saman viipaleen kaikilta matriisin riveiltä.
- ja jos haluaa tulostaa vain ensimmäisen sanan siitä erotetusta vaatii se oman käskynsä: echo ${muuttuja[@]%% *} - ja sekin toimii yli koko matriisin.:
- loopeila saa tehtyä nopeahkon skriptin joka tulostaa matriisin jokaisen rivin halutun kentän

echo ${muuttuja[1]%palloveikot*} tulostaa mitä lukee toisella rivillä sanan: palloveikot edessä
echo ${muuttuja[@]%palloveikot*} tulostaa matriisin jokaiselta riviltä mitä on kaikilla riveillä sanan palloveikot edessä.

echo ${muuttuja[@]//köksä/gastronominen_taitelija} muuttaa koko matriisissa kaikki sanat köksä sanaan gastronominen_taitelija
echo ${muuttuja[@]//ä/$(tput blink)ä$(tput sgr0)}  ennen englanniksi kirjoitetun väitöskirjan luovuttamista voi tarkistaa onko sinne jäänyt ä-kirjaimia -> koko teksti tulostuu siten että ä-kirjaimet vilkkuvat jolloin näkee hyvin jos niitä jossain on. Google&kumppanit on miljoonakertaa parempi tarkistamiseen - paitsi silloin harvoin kun se ei ole.

- kaikki nämä käskyt toimivat erittäin nopeasti - usein melkein yhtä nopeasti kuin sed. Miksei niistä puhuta että edes tiedettäisiin että tuomoisiakin käskyjä on? Koska  ne ovat tulosta monien virtuoosien vuosikausien ponnisteluista niin kuinka on mahdollista että niiden on annettu vaipua unholaan - kukaan ei ole edes jupissut vastaan? Ovatko ne liian tehokkaita - sillä valmisohjelmien reviiriähän nopeus ja tehokkuus ovat. Näissä rinkuloissa BASH:in omia valmisohjelmia ovat esimerkiksi sed ja awk - toki myös regex:ät grepin avulla - nykyäänhän ne kaikki ovat lähes kuolleet mutta aikoinaan niiden tekeminen on taannut leivän sadoille ihmisille.

14
Paniikki iski kun edellisten skriptien saaminen toimiaan useammissa koneissa oli kovin hidasta ja aloin ihmetellä minkä takia - onko jotain ihan perusteellista? Toki sitä perusteellista löytyi - mutta oikeastaan jo kauan sitten ilmennyttä: toimiminen olion kanssa jota luulee esimerkiksi matriisiksi mutta se onkin tekstijono.

Asiaa sotkee se että BASH:issa kaikki muuttujat ovat matriiseja ja niin on myös tekstijono - tekstijono on saman-nimisen matriisin jäsen nolla - ei käsittelyssä ole mitään ristiriitaa sillä matriisin missähyvänsä osoitteessa olevaa tekstijonoa käsitellään eritavalla kuin matriisia - koko homma saa alkunsa siitä että jos matriisin jäsentä ei määrätä niin oletetaan että kyseessä on jäsen nolla. Esitetään asia esimerkillä: tehtävänä on tulostaa muuttuja mutta siitä ei tiedetä onko se tekstijono vaiko matriisi - siis jos se muodostuu numeroista niin onko sen kuvaaja:
1
2
3
vaiko: 1 2 3. Tosin käytännössä molemmat tulostetaan yleensä: 1 2 3 jokatapauksessa koska käytännön isojen matriisien kunnollinen pystysuora esitys veisi niin paljon tilaa että se sotkisi tulosteen ihan käsittämättömäksi - joten tulosteestakaan ei voi päätellä onko tulostettu tekstijono vaiko matriisi. Ja koska tekstijonojen ja matriisien käsitely on erilaista täytyy kummallekin tehdä skriptistä oma versio ja päätellä aina mitä versiota kutsutaan. Mutta on asiaan toinenkin ratkaisu: muutetaan siellä matriisin jäsenessä nolla oleva tekstijono matriisiksi ja myöhemmin kutsutaan aina vain matriisi-versiota. Mutta tälle muutokselle tehtävän funktion tulee käyttää nimiparametria. Senjälkeen jokaisen tekstijonon tai matriisin paikalle kirjoitetaan: $(matrixsize muuttujan_nimi) ja sitten käsittellään aivankuin se olisi aina ollut matriisi.

- ensimmäinen vaikeus on tehdä matrixsize-funktio - mutta se on tehty jo ja toimivaksi havaittu. Mutta paljon pahempi vaikeus on saada virtuoosit uskomaan että se toimii sillä he eivät epä-uskossaan edes kokeile. Mutta tässä se on:
Koodia: [Valitse]
function matrixsize () { matriisi=($( echo ${apu#*=} | tr \" '\n' | sed '/^[[:space:]]/d' | sed 1d | sed '$ d')); read<<<${matriisi} $1 ;}

koe="kissa kuumalla katolla"   # tämä on koeteksti1 ja: koe=(kissa kuumalla katolla) # on koeteksti2. Siis matrixsize:lle voidaan antaa matriisikin.
matrixsize koe; echo ${koe[1]} # kutsussa tuo numero on joko matriisin jäsen numero tai tekstijonon sananumero

-------------------------------------

Mutta on asiaan helpomminkin hyväksyttävä osa-ratkaisu. Esimerkiksi kun joudut tulostamaan jotakin josta et tiedä onko se tekstijono tai matriisi :
Koodia: [Valitse]

function tulosta () {
apu=$(declare -p $1) 
case ${apu:9:1} in
a ) matriisi=($( echo ${apu#*=} | tr \" '\n' | sed '/^[[:space:]]/d' | sed 1d | sed '$ d')); echo ${matriisi[$2]} ;;
* ) tekstijonomatriisi=($(eval echo \$${1#*=})); echo ${tekstijonomatriisi[$2]}  ;;
esac ;}

koe="kissa kuumalla katolla" # tämä on koeteksti1 ja: koe=(kissa kuumalla katolla) # tämä on koeteksti2
tulosta koe 0 # kutsussa tuo numero on joko matriisin jäsen-numero tai tekstijonon sananumero (= monesko välilyöntien erottama sana se on)


- skripti on tavallaan vain ohje tulkille kuinka toimia - 'ratapihakaavio: kuinka asettaa vaihteet oikein' - joten toiminta hidastuu vain vähän.
- jos tämä skripti olisi kirjastossa niin tulostaminen olisi unelmaa.
- mikäli määräät:
Koodia: [Valitse]
matriisi=({1..10}); matriisi="1 2 3 4 5 6 7 8 9 10"; echo ${matriisi[@]} niin tulostuu: 1 2 3 4 5 6 7 8 9 10 2 3 4 5 6 7 8 9 10
- katsopa millainen sotku BASH:in kirjanpidossa vallitsee käskemällä: declare -p matriisi  niin tulostuu:
Koodia: [Valitse]
declare -a matriisi=([0]="1 2 3 4 5 6 7 8 9 10" [1]="2" [2]="3" [3]="4" [4]="5" [5]="6" [6]="7" [7]="8" [8]="9" [9]="10") -> status on edelleen matriisi ja mariisin jäsen nolla on tekstijono ja loput jäsenet vanhan matriisin arvoja.
- echo $matriisi kylläkin tulostaa ihan oikein ja muutenkin tuntuu sitä että kyseessä on vain kosmeettinen haitta.

15
Nyt täytyy laittaa foorumille talteen keskeneräinen työ sillä olen rähmäkäpälä ja tuhoan kotona oleat toimivat skriptit

Tarkoitus on tehdä jakauma edellsestä ja omassa koneessani se toimiikin hyvin.
Koodia: [Valitse]
rm -f ~/nano/data2; rm -f ~/nano/data3; touch ~/nano/data2; touch ~/nano/data3; readarray -t apu < ~/nano/data; for (( n=0; n<${#apu[@]}; n++ )); do echo $((${apu[$n]}/2000)) >> ~/nano/data2; done; sort -n ~/nano/data2 | uniq -c >~/nano/data3
# mutta tiedostossa  ~/nano/data3 ovat y ja x väärässä järjestyksessä joten niiden järjestys täytyy vaihtaa:
while read -r line; do set $line; echo $2 $1; done < ~/nano/data3 > ~/nano/data4 # siis saman lauseen sekä sisäänmeno että ulostulo voidaan uudelleensuunnata yhtaikaa
# tiedostossa ~/nano/data4 on paljon turhia rivejä joten poistetaan ne jotta käyrästä saisi paremmin selvää
cp <(sed -n '160,460 p' ~/nano/data4) ~/nano/data5
gnuplot -p -e 'set terminal postscript eps color enhanced;  set output "~/nano/pohjienjakauma.eps";set xlabel "aika"; set ylabel "aikojen jakauma"; plot "~/nano/data5"'

16
Olen jo pitkään epäillyt että BASH:in suoritusaikojen vaihteluissa on jonkinsortin säännöllisyyttä - siis että tulos hidastuu monta kertaa peräkkäin, siten taas nopeutuu - hidastuu - nopeutuu - ... nikotellenkin silointällöin - keskiarvon pysyessä melkolailla vakaana. Vaihtelu on havaittavissa time-käskylläkin mutta yleensä sen erotelu-kyky ei ihan riitä. Ei asialla enää nykyään merkitystä ole mutta se on mielenkiintoista että miksi time-käskyn erottelukyky loppuu juuri siihen mistä ongelmat alkavat.

Tutkitaan kuitenkin se vähä mikä pystytään - skripti kestää muuten varttitunnin - ensimmäiseksi tutkitaan kuinka pitkään BASH:illa kestää tehdä koodi sille annetusta skriptistä - muuten muut kielet polkevat paikallaan paljon kauemmin kuin BASH. Ja tämä tulkkaamiseen kuluva aika vaihtelee myös. 
- aluksi laitetaan laitetaan suoritukseen todella yksikertainen skripti ja mitataan aika siihen kun työ on valmis. Yksinkertaisin skripti on kaksoispiste elikä käsky olla tekemättä mitään -  mutta ei sitäkään prosessoriin kaksoispisteenä syötetä vaan tulkin täytyy tulkata kaksoispistekin ryhmäksi bittejä joten kyllä silloinkin lähdetään toimiin tulkin kautta - käskyn suorittamien ei sitten kestä juuri mitään. Funktio nano mittaa sitten kauanko tulkkaus ja sen jälkeinen käskyn suorittaminen kestävät. Grafiikka-ohjelma gnuplot esittää sitten tulokset graafisena.
- laitettuasi skriptin toimimaan voit rauhassa vaikka surffata.
- erottelukyky ajoitus-ohjelmalla nano on hyvä - mutta joku kyllä joskus höpertää - onko se nano itse selvinnee aikanaan.
- jokainen mittaustulos esitetään graafisessa kuvaajassa merkillä: + .
- tulos riippuu kaikesta mahdollisesta: kuinka hyvä tietokone on, mikä on lämpötila, sorsiiko onnetar ...
- tietokneen kaikilla sovelluksilla on pärstäkerroin jonka perusteella käyttöjärjestelmä arvostaa itseään yli kaiken, laittaa toisista jotkut pikakaistalle jossa odottelua on vähä ja jotkut joutuu odottamaan useammin ja pikkuisen kauemmin. Ja BASH kuuluu niihin pikkuisen kauemmin odottaviin. Vähäsen apua tuo käsky: sudo renice -20 -u käyttäjänimi. Myös sleep-käskyt autavat sillä ne sanovat käyttöjärjestelmälle: nyt olisi minun kannaltani sopiva aika odotella muiden työskennellessä - mutta aikaahan sleep-käskyt vievät.
- reaaliaika-käyttöjärjestelmillä ei tätä vikaa pitäisi olla - kokeiliskohan BASH:in reaaliaika-versiota?
- aika mitataan kirjoittamalla alku- ja loppuhetki kovalevy-tiedostoon. Kovalevylle kirjoittaminen ja sieltä lukeminen ovat kylläkin hitaita toimenpiteitä, mutta itseasiassa tässä ainoastaan annetaan kirjoitusmääräykset ja laitetaan kirjoitettava nopeaan bufferiin ja kaikki muu toimii ajoituksen jälkeen eikä se silloin enää tulokseen vaikuta.
- anna varmuuden vuoksi käsky: sudo apt install gnuplot   - ja tee mitä se määrää.
- jos kokeilet skriptien toimintaa niin kopioi koko koodi keralla päätteeseen sillä odotusajat ovat pitkiä.
- tuloksia voit katsoa tiedosto-selaimella. Jos et ole sortunut 'hajoita ja hallitse' tekniikkaan toisilla versioilla, toisilla työpöydillä, toisilla ... 'onhan ne paljon parempia'.
- näilä arvoilla mittaus kestää noin varttitunnin.
Koodia: [Valitse]
function nano () { date +%s%N > alkuhetki; $@ ; date +%s%N > loppuhetki; sleep 0.01; echo $(($(cat loppuhetki) - $(cat alkuhetki))) >> ~/nano/data ;}

kertoja=7500; rm -f ~/nano/data; mkdir -p ~/nano; touch ~/nano/data ; time for (( n=1; n<=$kertoja; n++ )); do nano : ; sleep 0.09; done

rm -f ~/nano/data2; rm -f ~/nano/data3; touch ~/nano/data2; touch ~/nano/data3; readarray -t apu < ~/nano/data; for (( n=0; n<${#apu[@]}; n++ )); do echo $((${apu[$n]}/2000)) >> ~/nano/data2; done; sort -n ~/nano/data2 | uniq -c >~/nano/data3
# mutta tiedostossa  ~/nano/data3 ovat y ja x väärässä järjestyksessä joten niiden järjestys täytyy vaihtaa:
while read -r line; do set $line; echo $2 $1; done < ~/nano/data3 > ~/nano/data4 # siis saman lauseen sekä sisäänmeno että ulostulo voidaan uudelleensuunnata yhtaikaa

# tiedostossa ~/nano/data4 on paljon turhia rivejä joten poistetaan ne jotta käyrästä saisi paremmin selvää
cp <(sed -n '160,460 p' ~/nano/data4) ~/nano/data5

gnuplot -p -e 'set terminal postscript eps color enhanced;  set output "~/nano/pohjienjakauma.eps";set xlabel "aika"; set ylabel "aikojen jakauma"; plot "~/nano/data5"'
Tuloksia voit selata työkalupalkin Files selaimella ( se on se näytön reunalla olevien kuvakkeiden joukko ja hiirellä osoittaen oikea kuvake kirjoittaa viereensä: Files).

17
Tein uuden version skriptistä joka laskee neliöjuuren kaikista sille annetuista reaaliluvuista mukaan lukien luvut tyyppiä:
1.234567e-96  elikä 0.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001234567
1.234567e96   elikä 1234567xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Varsinkin yksi ominaisuus skriptissä on erinomainen: sqrt 4 on 2, sqrt 9 on 3, sqrt 16 on 4 , sqrt 25 on 5 .... sqrt 2**58 on 536870912 -> ne ovat aina kokonaislukuja. Ihminen kyllä käsittää että kun ohjelma sanoo 9:n neliöjuureksi 2.99999999 niin todellinen arvo on 3 mutta onhan se luotettavampaa jos jo alunperin sanotaan sen olevan 3.
- tasaluku tulee myös kun juurrettava on 0.00000000000000000000000000000000000016 sillä tulos on silloin .000000000000000004 tai:4.0e-18
- sitämukaa kun skriptien toimintaa saa parannettua selviävät myös tulevat parannukset - nytkin seuraava parannus on vain toteutusta vailla.
- ja ennenkaikkea: numeromäärä on vain noin 9 numeroa mutta nopeus on melkein yhtähyvä kuin parhaimmilla BASH:in matematiikkaohjelmilla.
- ajoitusmenetelmä nano antaa oikean ajan ainakin mikrosekunnin tarkkuudella sillä se että aika vaihtelee kerrasta toiseen johtuu Linuxista a BASH:in kannalta aikaa kuluu tosiaan senverran kun näytetään.

- muuten kun olet tulkannut funktion (=ajanut sen kertaalleen) niin saat siitä intendoidun listauksen käskyllä: type -a funktion_nimi -> esimerkiksi: type -a to_sci. Siinä ovat jopa kommentit mukana oikeissa kohdissa jos niitä alunperinkään oli. Toisaalta kun olet ajanut funktion niin tulkki tekee koneen muistiin tällaisen 'yksirivisen' esityksen funktiosta - nämä minun esitykseni ovat juuri tällaisia 'yksirivisiä' sillä ne säästävät tilaa ja aikaamyötä niitä oppii lukemaan ja myös tekemään paljon nopeammin. Tässävaiheessa kommentit ovat vielä mukana, mutta kun tulkki tosiaan ajaa funktion niin kommentit stripataan kuutamolle ihan ensimmäiseksi. 
- kokeillessa toimiiko koodia se kopioidaan kokonaisuudessaan leikepöydälle (komannolla ctrl-c), liimataan päätteeseen (komennolla ctrl-v)ja painetaan enter.
- kokeiu muilla arvolla: paina nappia: nuoli-ylöspäin, editoi ja paina enter.

Koodia: [Valitse]
function nano () { alkuhetki=$(date +%s%N); $@; loppuhetki=$(date +%s%N);echo 'laskenta kesti: '$(($loppuhetki-$alkuhetki))' nanosekuntia' ;}
function sqrt () { apu=${1##+(0)}; [[ $apu ]] || { echo 0; return ;} # lausetta tarvitsee vain kun lasketaan:  sqrt 0  . Tai: sqrt 00000....
function to_sci () { # funktion voi määritellä funktiossa. Kommentti alkaa merkillä # ja loppuu joko kaksoispisteeseen tai rivinsiirtoon.
[[ $1 =~ e ]] && { echo $1; return ;} || { apu=$1; apu=${apu//[-+]/}; apu=${apu##+(0)}; int=${apu%%.*};[[ ${apu//[^.]/} ]] && desimaaliosa=${apu##*.} || desimaaliosa=0; [[ $int ]] && { expo=${#int}; echo ${int:0:1}.${int:1}$desimaaliosa'e'$(($expo-1)) ;} || { apu=${desimaaliosa%%[1-9]*}; ekspo=$((${#apu}+1)); desimaaliosa=${desimaaliosa:$(($ekspo-1)):1}.${desimaaliosa:$(($ekspo))}; desimaaliosa=${desimaaliosa%.}; echo $desimaaliosa'e'-$ekspo ;} ;} ;}  # oli: $(($ekspo))}; echo $desimaaliosa'0e'-$ekspo

apu=$(to_sci $1); mant=${apu%%e*}; apu=${apu##*e}; apu=${apu//+0/}; apu=${apu//-0/-}; (( $apu & 1 )) && kerroin=10 || kerroin=1; expo=$(($apu/2));   
in=${mant//./}"000000000000000000"; in=${in:0:17}
sqrt=2147483648  # 2^31
delta=1073741824 # 2^30  # tämä tulee voida jakaa jatkuvasti kahdella siten että jako menee aina tasan
for ((i=0;i<32;i++)); do # binääri-haun looppi alkaa
   x=$(($sqrt*$sqrt/$kerroin))
   (( $x>=$in )) && sqrt=$(($sqrt-$delta)) || sqrt=$(($sqrt+$delta))
   delta=$(($delta/2))
   (( $delta )) || delta=1  # echo $((1/2)) lasketaan nollaksi - oikein pyöristettynä se on 1
done
apu=00000000000000000000000000000000000000000000000000$sqrt'000000000000000000000000000000000000000000000';apu=${apu:0:$((51+$expo))}.${apu:$((51+$expo))}
luku=${apu##+(0)}; [[ ${luku//[^.]/} ]] && luku=${luku%%+(0)}; luku=${luku%.}

echo; echo -n "neliöjuuri luvusta: $juurrettava on: $luku"; [[ $luku =~ \. ]] && { echo -n " tai tieteellisesssä muodossa: "; to_sci $luku ;} || echo ;}
   
juurrettava=1.1234568e-99;nano sqrt $juurrettava

18
Parantelin 36-numeron liukuvan pilkun kertolaskua - sen kerrottaviksi voi antaa kaksi liukuvan pilkun 18-numeroista kerrottavaa. Poistin vanhan koodin ja laitoin tähän uuden.

Ja vaikka bc antaa oikean tuloksen johon verrata niin muuten bc ei osallistu laskentaan ollenkaan - sentakia kutsut ovatkin monimutkaisia. Mutta normaalisti koko bc:n voi jättää pois ja silloin kutsu on: kerro18 $luku1 $luku2

- esimerkiksi tulos laskusta: .00900007567899123 * 900.07000012345678  on: 8.1006981175007567491845709040394   - ja lasku kestää vain 1ms - bc:llä lasku  kestää 3ms.
Koodia: [Valitse]


function kerro18 () {
tulosta=: # yhdessä paikassa päätetään tulostetaanko välituloksia. Vaihtoehdot:tulosta=echo ja tulosta=:
[[ ${#1} -gt 18 || ${#2} -gt 18 ]] && echo laskettavissa liikaa numeroita && return
$tulosta "annetut numerot: "$1 $2
[[ ${1:0:1} = - || ${2:0:1} = - ]]  && merkki=- || merkki=''
[[ ${1:0:1} = - && ${2:0:1} = - ]]  && merkki=''
apu1=${1//\-/}; apu2=${2//\-/}
desimaaliosa1=${1##*.};
desimaaliosa2=${2##*.};
[[ ! ${apu1//[^.]/} ]] && desimaaliosa1=''
[[ ${apu1//[^.]/} ]] && { luku1=${apu1:0:18}; kokonaisluku=0 ;} || { luku1=${apu1:0:18}"."; kokonaisluku=1 ;}
[[ ! ${apu2//[^.]/} ]] && desimaaliosa2=''
[[ ${apu2//[^.]/} ]] && { luku2=${apu2:0:18}; kokonaisluku=0 ;} || { luku2=${apu2:0:18}"."; kokonaisluku=$(( 1 & $kokonaisluku )) ;}
 desimaaleja=$((${#desimaaliosa1}+${#desimaaliosa2})); $tulosta desimaaliosa1:$desimaaliosa1"   desimaaliosa2:"$desimaaliosa2"   desimaaleja:"$desimaaleja
luku1=000000000000000000${luku1//./}
luku2=000000000000000000${luku2//./}
a=${luku1: -18:9}; b=${luku1: -9}
c=${luku2: -18:9}; d=${luku2: -9}; $tulosta $a' '$b; $tulosta $c' '$d
luku1=00000000000000000000000000000000000000$((10#$b*10#$d))
luku2=00000000000000000000000000000000000000$((10#$d*10#$a))"000000000"
luku3=00000000000000000000000000000000000000$((10#$c*10#$b))"000000000"
luku4=00000000000000000000000000000000000000$((10#$a*10#$c))"000000000000000000"
luku1=${luku1: -36} ; $tulosta $luku1
luku2=${luku2: -36} ; $tulosta $luku2
luku3=${luku3: -36} ; $tulosta $luku3
luku4=${luku4: -36} ; $tulosta $luku4; $tulosta
luku11=${luku1:0:18}
luku12=${luku1:18}; $tulosta a$luku11' 'b$luku12
luku21=${luku2:0:18}
luku22=${luku2:18}; $tulosta c$luku21' 'd$luku22
luku31=${luku3:0:18}
luku32=${luku3:18}; $tulosta a$luku31' 'b$luku32
luku41=${luku4:0:18}
luku42=${luku4:18}; $tulosta c$luku41' 'd$luku42;$tulosta
summa1=$((10#$luku12+10#$luku22+10#$luku32+10#$luku42)); $tulosta summa1:$summa1
summa1pituus=${#summa1}; ylivuoto=0; (( $summa1pituus >= 19 )) && ylivuoto=${summa1:0: -18} && summa1=${summa1:1}
summa1=000000000000000000$summa1; summa1=${summa1: -18} ;$tulosta ylivuoto:$ylivuoto' summa1:'$summa1
summa2=$((10#$luku11+10#$luku21+10#$luku31+10#$luku41+$ylivuoto)); $tulosta summa2:$summa2
 
(( $summa2 )) && : || summa2=000000000000000000
(( $kokonaisluku )) && tulos=${summa2/*(0)/}$summa1 || { apu=$summa2$summa1; tulos=${apu:0: -$desimaaleja}.${apu: -$desimaaleja} ;}
echo $merkki${tulos##+(0)}
echo tulos laskusta: $1 \* $2  . Ylärivi on bc:stä ja alarivi tästä skriptistä. ;}

clear
echo kun tulos siirtyy uudelle kymmenluvulle on syytä tarkistaa että desimaaalipisteen paikka siirtyy oikealla hetkellä
luku1=3.16227766; luku2=3.16227766;                  echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2     
luku1=3.16227767; luku2=3.16227767;                  echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2     

luku1=1 ; luku2=1 ;                                 echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=-1 ; luku2=1;                                 echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=1 ; luku2=-1;                                 echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=-1 ; luku2=-1;                                echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=.00900007567899123; luku2=900.07000012345678; echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=111111.11111111111; luku2=123456789012345.67; echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2 
luku1=10; luku2=10                                ; echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=999999999999999999; luku2=999999999999999999; echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=.9; luku2=2;                                  echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=.99999999999999999; luku2=.99999999999999999; echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=.00000000000000001; luku2=.00000000000000001; echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2   
luku1=10000000000000000; luku2=.0000000000000001;   echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2
luku1=.0000000000000001; luku2=10000000000000000;   echo ------; echo; bc<<<"scale=40; $luku1*$luku2"; time kerro18 $luku1 $luku2   




 

19
 
Koodia: [Valitse]
function potenssi () {
tulosta=: # yhdessä paikassa päätetään tulostetaanko osa-tehtävien jälkeen välituloksia. Vaihtoehdot:tulosta=echo ja tulosta=:
for (( n=1; n<=$(($2-1)); n++ )); do # for n in $(seq $(($2-1))); do       
luku1=${1:0:18}; [[ $n = 1 ]] && luku2=$luku1 || luku2=$merkki${tulos##+(0)}; luku2=${luku2:0:18}
$tulosta "annetut numerot: $1 $2"
[[ ${1:0:1} = - ]]  && merkki=- || merkki=''
[[ ${1:0:1} = - && ${2:0:1} = - ]]  && merkki=''
apu1=${luku1//\-/}; apu2=${luku2//\-/}
desimaaliosa1=${luku1##*.};
desimaaliosa2=${luku2##*.};
[[ ! ${apu1//[^.]/} ]] && desimaaliosa1=''
[[ ${apu1//[^.]/} ]] && { luku1=${apu1:0:18}; kokonaisluku=0 ;} || { luku1=${apu1:0:18}"."; kokonaisluku=1 ;}
[[ ! ${apu2//[^.]/} ]] && desimaaliosa2=''
[[ ${apu2//[^.]/} ]] && { luku2=${apu2:0:18}; kokonaisluku=0 ;} || { luku2=${apu2:0:18}"."; kokonaisluku=$(( 1 & $kokonaisluku )) ;}
 desimaaleja=$((${#desimaaliosa1}+${#desimaaliosa2})); $tulosta desimaaliosa1:$desimaaliosa1"   desimaaliosa2:"$desimaaliosa2"   desimaaleja:"$desimaaleja
luku1=000000000000000000${luku1//./} #0
luku2=000000000000000000${luku2//./}
a=${luku1: -18:9}; b=${luku1: -9}
c=${luku2: -18:9}; d=${luku2: -9}; $tulosta $a' '$b; $tulosta $c' '$d
luku1=00000000000000000000000000000000000000$((10#$b*10#$d))
luku2=00000000000000000000000000000000000000$((10#$d*10#$a))"000000000"
luku3=00000000000000000000000000000000000000$((10#$c*10#$b))"000000000"
luku4=00000000000000000000000000000000000000$((10#$a*10#$c))"000000000000000000"
luku1=${luku1: -36} ; $tulosta $luku1
luku2=${luku2: -36} ; $tulosta $luku2
luku3=${luku3: -36} ; $tulosta $luku3
luku4=${luku4: -36} ; $tulosta $luku4; $tulosta
luku11=${luku1:0:18}
luku12=${luku1:18}; $tulosta a$luku11' 'b$luku12
luku21=${luku2:0:18}
luku22=${luku2:18}; $tulosta c$luku21' 'd$luku22
luku31=${luku3:0:18}
luku32=${luku3:18}; $tulosta a$luku31' 'b$luku32
luku41=${luku4:0:18}
luku42=${luku4:18}; $tulosta c$luku41' 'd$luku42;$tulosta
summa1=$((10#$luku12+10#$luku22+10#$luku32+10#$luku42)); $tulosta summa1:$summa1
summa1pituus=${#summa1}; ylivuoto=0; (( $summa1pituus >= 19 )) && ylivuoto=${summa1:0: -18} && summa1=${summa1:1}
summa1=000000000000000000$summa1; summa1=${summa1: -18} ;$tulosta ylivuoto:$ylivuoto' summa1:'$summa1
summa2=$((10#$luku11+10#$luku21+10#$luku31+10#$luku41+$ylivuoto)); $tulosta summa2:$summa2 
(( $summa2 )) && : || summa2=000000000000000000
(( $kokonaisluku )) && tulos=${summa2/*(0)/}$summa1 || { apu=$summa2$summa1; tulos=${apu:0: -$desimaaleja}.${apu: -$desimaaleja} ;}
done
echo; echo tulos laskusta: $1 \^ $2   
# echo Ylärivi on varmasti oikea arvo bc:stä vertaamista varten ja alarivi tästä skriptistä:;bc<<<"scale=14; $1^$2"
(( $2 & 1 )) && echo -n $merkki; tulos=${tulos##+(0)}; echo ${tulos:0:14} ;}

time potenssi -1.23456789012345 10 # oikea arvo bc:stä vertaamista varten: bc<<<"scale=14; $1^$2"


20
En ole aikaisemmin laittanut foorumille skriptiä desimaalilukujen potenssiin korottamista varten sillä yksinkertaisen skriptin lukualue on onnettoman pieni eikä se korkeampia potensseja pysty käsittelemään ollenkaan - skripti on kylläkin tosi-nopea. Myöhemmin lisään koodiin suurempien lukujen ratkaisemiseksi tarvittavat osat.
- jos potenssiin korotettava luku on kokonaisluku niin tässä skriptissä sen perään lisätään .0 . Elikä: [[ $1 =~ \. ]] || set -- $1'.0' $2 -> set muodostaa uuden parametrijoukon (elikä nuo $1 $2 $3 $4 ... nimiset) sille annetuista muuttujista - nollaten kaikki vanhat - siis kaikki jolle halutaan joku arvo on liitettävä mukaan - joten jos tässä ei olisi lopussa tuota $2:ta niin $2 jäisi määrittelemättä - mutta tällätavoin uusi $2 saa vanhan $2:n arvon.
- kaikilla käskyillä voi olla parametreja ja niin myös käskyllä: set. Tässä heti set:in jälkeen on -- ja se kertoo tulkille että set:in omat parametrit on tässävaiheessa jo annettu joten seuraavassa luvussa mahdollisesti oleva - on miinusmerkki.
- muuten: ehto && teko1; teko2 || teko3 täytyy yleensä merkitä: ehto && { teko1; teko2 ... ;} || teko3 tai se merkitsee ihan muuta kuin on tarkoitus.
- laskettavien edessä on usein:10# . Se johtuu siitä että luvun ensimmäinen merkki saattaa desimaaleilla toimittaessa olla nolla ja kun luvussa on etunolla siirryttään laskuissa oktaali-järjestelmään ellei ole käskyä pysyä desimaalijärjestelmässä. Sitä kutsutaan oktaali-ansaksi ja sen inhottavin piirre on se että mikäli laskettavissa ei ole numeroita 8 tai 9 lasku onnistuu ihan hyvin - mutta tulos on oktaaliluku vaikka sitä luullaankin desimaaliluvuksi. Ja koska kyse on BASH:ista niin tottakai tuolla 10#:llä on poikkeuskin: negatiiviset luvut eivät sitä tarvitse ja peräti aiheuttavat virheen. Siksi tuo pikä litania:
Koodia: [Valitse]
[[ ${1:0:1} == - ]] && tulos=000000000000000000$((${1//./}**$2)) || tulos=000000000000000000$((10#${1//./}**$2))

Ja sitten itse skripti:
Koodia: [Valitse]
function potenssi () { [[ $1 =~ \. ]] || set -- $1'.0' $2; [[ ${1:0:1} == - ]] && tulos=000000000000000000$((${1//./}**$2)) || tulos=000000000000000000$((10#${1//./}**$2)); des=${1#*.};[[ $(($2*${#des})) -lt 19 ]] && { apu=${tulos:0: -$(($2*${#des}))}.${tulos: -$(($2*${#des}))}; apu=${apu##+(0)}; apu=${apu%%+(0)}; echo ${apu%.} ;} || echo liian iso luku;}
 
# tarkistuksia:
a=-.2; b=10; time potenssi $a $b    # .0000001024
a=.2; b=10; time potenssi $a $b     # .0000001024
a=-2; b=10; time potenssi $a $b     # 1024
a=2; b=10; time potenssi $a $b      # 1024
a=2.0; b=10; time potenssi $a $b    # 1024
a=4.9999; b=4; time potenssi $a $b  # 624.9500014999800001  # time bc -l <<< "4.9999^4"
a=0.11; b=9; time potenssi $a $b    # .000000002357947691
a=0.9; b=9; time potenssi $a $b     # .387420489
a=2.11111; b=4; time potenssi $a $b # liikaa numeroita

Sivuja: [1] 2 3 ... 35