Kirjoittaja Aihe: Ohjeita shell-skriptaukseen (bash)  (Luettu 369514 kertaa)

petteriIII

  • Käyttäjä
  • Viestejä: 689
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #320 : 14.10.24 - klo:14.36 »
Aikoinaan ei annettu pienintäkään toivoa sille että kaksiulotteiset matriisit toimisivat joskus - että voisi tehdä funktion hakemaan vapaa-muotoisesta matriisista yksi jäsen kun nimetään matriisi ja sen rivi ja sarake. Sellaista kaivattiin jo vuosikymmeniä sitten ja monet yrittivät sellaista tehdäkin mutta asia ei edistynyt vähääkään. Kuitenkin BASH on aina osannut kaksiulotteisten matriisien käsittelemisen mutta skriptiä sitävarten ei vain ole tehty koska ei osattu valita oikeita käskyjä - löytyi ne kyllä äskettäin mutta koska kymmenen vuotta sitten BASH:iin tuli paremmat toiminnot niin tämä on niillä tehty sillä nopeutta tuli roimasti lisää.

En alkuunkaan usko, ettei kukaan ole aikoinaan tehnyt tätä toimintoa sillä se on niin yksinkertainen että eiköhän se ole kuulunut jo alkuperäisiin suunnitelmiin siitä miten matriisien tulee toimia BASH:issakin.

Mutta koska matriisin nimi passataan nimenä eikä arvoina on tässä paljon normaalista poikkeavaa. Käsiteltävät matriisit voivat olla minkä muotoisia tahansa ja muodostettu vaikka minkälaisista olioista: kokonaisluvuista, desimaalivuista, tekstistä ja vaikka nuolenpää-kirjoituksesta ...  Nopeuskin on BASH:iksi ihan siedettävä.

Nykyvaatimusten mukaan tämä on sittenkin kelvottoman hidas mutta tämä onkin vain osoitus että kyllä BASH:issa toimivat myös kaksi-ulotteiset matriisit - ja samalla periaatteella kolmi-ulotteisetkin.

On täysin mahdotonta saada minkäänlaista käsitystä BASH:in kyvyistä koska niin paljon mahdottomaksi väitettyä on osottautunut toimivaksi - ja kun aikaisemmin isot työt kestivät sekunteja niin nyt niistä monet kestävät millisekunteja. Vaikka pitää edelleen paikkansa että BASH on ohjelmointikieleksi rääpäle niin 'tunnelin päässä on valoa'.

---

esimerkki - ensin tehdään matriisi - voisi sen lukeakin jostain - ja sitten haetaan siitä arvo rivitä:2  sarakkeesta 8:
Koodia: [Valitse]
matriisi=([0]="1 2 3 4 5 6 7 8" [1]="a b c d e f g h" [2]="1 22 333 4444 55555 666666 7777777 8.8888e-88"); echo tämmöinen matriisista tuli:; echo; printf "%s\n" "${matriisi[@]}" | column -t; echo
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))} ;}

time hae_arvo_matriisista matriisi 3 8
- ajan kulumisen kannalta on melkein yksilysti mitä numeroiden paikalla on: pitkää tai pätkää, numeroita, kirjaimia, mitähyvänsä merkkejä.
- samoin matriisin koko vaikuttaa suoritusaikaan vain vähäsen

petteriIII

  • Käyttäjä
  • Viestejä: 689
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #321 : 16.10.24 - klo:11.40 »
Matriisin määrittelyn voi tehdä toisinkin: voi kirjoittaa matriisin välittömästi skriptiin ihan semmoisena kuin se on -  kuten esimerkissä on tehty. Matriisi-määrittelyn voi silloin myös kopioida jostakin.
Matriisimäärittely näyttää vähän omituiselta mutta se on kopioinnin kannalta ihanteellinen:
Koodia: [Valitse]
unset matriisi; readarray matriisi<<<"! ' ¤ % & / ( )
@ £ $ ‚ { [ ] }
ä ö å Ä Ö Å ½ §
1 22 333 4444 55555 666666 7777777 -88.88e-88";  echo tämmöinen matriisista tuli:; echo; printf "%s\n" "${matriisi[@]}" | column -t; echo
- matriisi voi olla minkäkokoinen ja muotoinen tahansa ja useimmat merkit kelpaavat - mutta esimerkiksi: jos ulkona on ' niin sisälle kelpaa vain " ja jos ulkona on " niin sisälle kelpaa vain ' . Sama sääntö on ainakin sed:issä.
- toki matriisi-kuvauksen voisi kirjoittaa yhteen pötkyynkin mutta silloin kopioinnista tulisi vaikeaa ja työlästä kopioida se jostakin:
readarray matriisi<<<"1 2 3 4 5 6 7 8"$'\n'"a b c d e f g h"$'\n'"1 22 333 4444 55555 666666 7777777 88.88e-88"
- muuten tuo alussa oleva unset nollaa matriisin niinkuin sitä ei olisi ollutkaan ja aloitetaan puhtaalta pöydältä. Unset olisi hyvä lisätä aina mudostamisen alkuun sillä se ei vie aikaa ja esimerkiksi kun matriisit ovat todella suuria niin se on jopa tarpeen.
- kirjastokielto ja huonot ohjeet - man-sivut, BASH-raamattu ja virtuoosit - aiheuttavat sen että BASH:issa on pakkokin ottaa kopiointiin uusi asenne.
« Viimeksi muokattu: 16.10.24 - klo:13.59 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 689
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #322 : 17.10.24 - klo:15.59 »
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.