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

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • 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 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

« Viimeksi muokattu: 15.11.24 - klo:14.17 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #321 : 16.10.24 - klo:11.40 »
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.
« Viimeksi muokattu: 24.11.24 - klo:12.24 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • 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.

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #323 : 21.10.24 - klo:15.23 »
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.
« Viimeksi muokattu: 27.10.24 - klo:10.40 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #324 : 27.10.24 - klo:10.47 »
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.

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #325 : 30.10.24 - klo:14.56 »
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 




« Viimeksi muokattu: 12.11.24 - klo:11.21 kirjoittanut petteriIII »

Whig

  • Käyttäjä
  • Viestejä: 365
  • puppu-generaattori
    • Profiili
    • localhost
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #326 : 06.11.24 - klo:11.11 »
Nyt lyö päässä pahasti tyhjää mutta minulla on tiedosto jossa on sanoja yksi per rivi (sanat.txt):

sana1
sana2
sana3
sana4

Sitten minun pitäisi saada scripti joka ajaa haluamani komennon käyttäen tuossa toisessa tiedostossa olevia sanoja niin kauan, kuin sanoja riittää.

Eli scriptissä olisi vaikka jotain tyyliin:

mkdir (tähän haettu sana sanat.txt:stä)
chmod +x (tähän haettu sana sanat.txt:stä)

Ja tämä scripti tosiaan toistaisi tätä samaa kunnes jokainen rivi sanat.txt:stä olisi käyty läpi.

nm

  • Käyttäjä
  • Viestejä: 16468
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #327 : 06.11.24 - klo:14.48 »
Nyt lyö päässä pahasti tyhjää mutta minulla on tiedosto jossa on sanoja yksi per rivi (sanat.txt):

sana1
sana2
sana3
sana4

Sitten minun pitäisi saada scripti joka ajaa haluamani komennon käyttäen tuossa toisessa tiedostossa olevia sanoja niin kauan, kuin sanoja riittää.

Eli scriptissä olisi vaikka jotain tyyliin:

mkdir (tähän haettu sana sanat.txt:stä)
chmod +x (tähän haettu sana sanat.txt:stä)

Ja tämä scripti tosiaan toistaisi tätä samaa kunnes jokainen rivi sanat.txt:stä olisi käyty läpi.

Onnistuu esimerkiksi tähän tapaan while-silmukalla ja read-komennolla:

Koodia: [Valitse]
#!/bin/bash

INPUT="sanat.txt"

while read -r LINE
do
    echo "Käsitellään: $LINE"
    # Lisää tähän rivikohtaisia komentoja:
    # mkdir "$LINE"
    # chmod +x "$LINE"
done < "$INPUT"

Whig

  • Käyttäjä
  • Viestejä: 365
  • puppu-generaattori
    • Profiili
    • localhost
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #328 : 07.11.24 - klo:09.50 »
Onnistuu esimerkiksi tähän tapaan while-silmukalla ja read-komennolla:

Kiitoksia tämä toimi täydellisesti siihen mitä tarvitsin =)

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #329 : 06.01.25 - klo:16.51 »
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.
« Viimeksi muokattu: 12.01.25 - klo:07.10 kirjoittanut petteriIII »

petteriIII

  • Käyttäjä
  • Viestejä: 695
    • Profiili
Vs: Ohjeita shell-skriptaukseen (bash)
« Vastaus #330 : 16.01.25 - klo:18.29 »
Myös BASH-raamatussa on monia assembler-tyyppisiä käskyjä - lukeaksesi ne päätteessä kirjoita: man bash ja sitten kirjoita: / ja:Parameter Expansion . Siis kirjaimellisesti ottaen tuo sanoo että kyse ei ole käskyistä ollenkaan vaan tavasta esittää muuttujia toisella tavalla kuin ennen. Onhan teoria mukava tuntea mutta käytännössä sillä ei ole paljoakaan merkitystä koska nuo 'parametrien laajennokset' esitetään siten etteivät virtuoositkaan saa selvää niiden eduista ja taviksille ne ovat usein hepreaakin. Eikä siellä edes ole suurta osaa noista assembler-tyyppisistä käskyistä - mutta kyllä ne lukea kannattaa. Eikä esimerkkejä - eihän asia vaikea ole, mutta kun ei heti alkuun saa käsitystä mistä on kyse niin useimmat ohittavat ne kokonaan.

'Parameter Expansiot' tarvitsevat toimiakseen jonkun käskyn joka niitä käyttää - echo:n tai merkin = esimerkiksi. Nuo 'Parameter Expansiot' ovat kuin käskyn kytkimiä (=parametreja) joten ne toteutetaan suurinpiirtein yhtä nopeasti kuin käsky muutenkin. Mutta niitä 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 jossain historian kätköissä ja vain muutamia on saanut kaivettua 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.
- ja echo:han toimii matriisienkin kanssa joten niin toimii tämäkin - ja kokoajan C-kielen nopeudella.
- joten 'Parameter Expansiot' 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. Joten joku tosi isokenkäinen riensi 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 oikeiden vastauksien 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.

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.
« Viimeksi muokattu: 27.01.25 - klo:14.04 kirjoittanut petteriIII »