Kirjoittaja Aihe: Skriptiajuri  (Luettu 129475 kertaa)

petteriIII

  • Käyttäjä
  • Viestejä: 665
    • Profiili
Vs: Skriptiajuri
« Vastaus #80 : 01.05.24 - klo:17.54 »
Miksi BASH:ista esittään kaikkialla niin vähän esimerkkejä? Ja miksi kaikki lähetyvät ongelmia samalta suunnalta vaikka BASH on niin laaja että kaikkeen on lukemattomia lähestymistapoja? Johtuuko se siitä ettei ohjeita tehdä vaan ne kopioidaan eikä niitä ohjeitakaan päivitetä koskaan - tosin joillain harvoilla verkkosivuilla mainitaan puolihuolimattomasti että 'tämmöistäkin uutta surkeutta löytyy'. BASH:ia tosiaan kehittää vain yksi ukko - ansiokkaasti kehittääkin ja varmaankin apujoukon kera - mutta mieleen tulee ettei hänkään halua sohia ampiaispesää tarpeettomasti.

Esimerkiksi 1+1 voidaan laskea ainakin kahdella yleisessä käytössä olevalla tavalla: ensinnäkin se normaali 'echo $((1+1))', se toinen tapa on : + 1 1  .
- mattematiikamoottori on kummassakin sama - tuo: $(($1+$2))
- kummessakin laskutavassa apuna täytyy olla funktio: siinä normaalissa on BASH:in sisäinen funktio nimeltään echo ja toisessa itsetehtävä funktio nimeltään +   .

Funktion nimeksi voidaankin määrätä melkein mitähyvänsä, esimerkiksi:
Koodia: [Valitse]
function + () { echo $(($1+$2)) ;}
- laskussa $(($1+$2)) + on matemaattinen merkki eikä funktiokutsu joten kyseessä ei ole rekursio (eli funktio ei kutsu itseään)
- kun annetaan käsky: + 1 2  niin se tulostaa 3 - mikäli löytyy tuo funktio nimeltään: +  .

Nimeltään tuo juohea laskutapa '+ 1 2' on käänteinen Puolalainen ja koska se vaatii BASH:issa käyttäjää tekemään itse tarvittavat funktiot niin käänteistä Puolalaista kannattaa käyttää vain kun matematiikkaa on tosipaljon. Ei tuota käänteistä Puolalaista tosin enää juuri koskaan käytetä.
- esimerkiksi laskuohjelman bc isä nimeltään dc oli käänteistä Puolalaista - se on koneelle helpompaa mutta ihmiselle niin vaikeaa että sille tehtiin kuori-ohjelma nimeltään bc joka muuttaa ihmisen ajatukset koneelle sopivammaksi käänteiseksi Puolalaiseksi. Onkohan käänteinen Puolalainen parempikin matikassa koska noin täytyi toimia?

petteriIII

  • Käyttäjä
  • Viestejä: 665
    • Profiili
Vs: Skriptiajuri
« Vastaus #81 : tänään kello 12:17 »

Yksi menetelmä etsiä tekstistä jotakin on muodostaa tuosta etsittävästä muotti ja ajaa teksti muotista läpi jolloin kaikki muotin mukainen tarttuu muottiin. Käytännössä toimitaan seuraavasti:

- etsittävän rakennetta kuvataan oliolla nimeltä regex: regex on muotti jonka määräysten mukaan etsittävän tyyppiset muuttujat on koottu - esimerkiksi päivämäärän muotti on: [0-9]+:[0-9]+:[0-9]+
- tässä paikassa merkki + merkitsee: yksi tai useampi samanlainen kuin on edessäkin.
- monille merkeille tulkki antaa asiayhteydestä riippuvan  erikoismerkityksen - useimmilla merkeillä on aina sama merkitys mutta esimerkiksi merkillä: * niitä on monia. Jos ei haluta tulkin antavan merkille erikoismerkitystä kirjoitetaan sen eteen kenoviiva - siis esimerkiksi: \*
- kun tekstin jokaista sanaa sovitellaan tuohon muottiin niin kun muotti sopii niin kyse on päivämäärästä.
- regex:ää on totuttu käyttämään jonkun apu-ohjelman avulla - esimerkiksi grep:in avulla ja kyllähän sillä omat etunsa onkin, mutta BASH kykenee useisiin regex:iin itsekin ja silloin kun BASH kykenee niin grep jää surkeasti kakkoseksi.
- myös tuo regex-maailma on valtavan suuri - katsopa verkkosivua: https://www.regexbuddy.com/. Ja samatyyppisiä sivuja on monia muitakin.

haku kokonaisuudessaan:
Koodia: [Valitse]
teksti="höpinää 17:06:23 lisää höpinää"; regex="[0-9]+:[0-9]+:[0-9]+"
[[ "$teksti" =~ $regex ]] && echo "tekstissä on päiväys:$BASH_REMATCH"
- tuosta regexään:n sopivasta muodostetaan aina BASH:issa muuttuja $BASH_REMATCH.

---

Mutta päiväys voidaan jakaa osiin: tuntiin, minuuttiin ja sekuntiin - ja mikäli regex on jakamista silmäälläpitäen muodostettu niin kukin näistä osista talletetaan omaan BASH_REMATCH[numero] nimiseen muuttujaan. BASH_REMATCH:ia selvitetään kaikkialla juurta jaksain - ja ehkäpä joku saa niistä selityksistä selvääkin. Mutta esimerkkejä ei esitetä; siis sellaista yksinkertaista skriptiä jossa tulostetaan BASH_REMATCH, BASH_REMATCH[1], BASH_REMATCH[2], BASH_REMATCH[3] ... jotta asiasta tulisi rautalankamalli jota ei voi käsittää väärin - tai oikeastaan että asian voisi nopeasti edes käsittää. Koetetaanpa nyt esitää asia ymmärrettävästi:

- BASH_REMATCH:ia käytettäessä regex:ät on jaettu suluilla osiin ja jokainen sulkupari muodostaa uuden muuttujan nimeltään:  BASH_REMATCH[1], BASH_REMATCH[2], BASH_REMATCH[3] ... ja niiden kokonaisuuden nimeltä: BASH_REMATCH. Esimerkiksi päivämäärää kuvaava regex jaetaan:
Koodia: [Valitse]
([0-9]+):([0-9]+):([0-9]+)   

Esimerkki:
Koodia: [Valitse]
teksti="höpinää 17:06:23 lisää höpinää"; regex="([0-9]+):([0-9]+):([0-9]+)"   
[[ "$teksti" =~ $regex ]] && echo "tekstissä seuraava palanen täytti koko regex:än: $BASH_REMATCH - ja sen osat: tunti:${BASH_REMATCH[1]} minuutti:${BASH_REMATCH[2]} sekunti:${BASH_REMATCH[3]}"
- mikäli koko regex ei täyty niin ei tulosteta mitään - elikä 2013:06 ei tulosta mitään.
- siis jokaisesta regex:än (....)-kentästä muodostuu uusi BASH_REMATCH[numero] - ja numerointi alkaa ykkösestä.
- muuten teksti voi olla matriisikin:
Koodia: [Valitse]
${teksti[@]}    - silloin tosin saadaan vain ensimmäinen joka sopii.
- kieliasetukset vaativat skriptiin omat muutoksensa - näillä määrityksillä tämä toimii Suomessa.
 
toinen esimerkki:
Koodia: [Valitse]
[[ "012 a34567b89cdefgh" =~ ([a-z])[0-9]*([a-z])[0-9]*([a-z]) ]] && {
      echo "- kolmeriviä selitystä: REMATCH:it tehdäån kohdassa:[[ "012 a34567b89cdefgh" =~ ([a-z])[0-9]*([a-z])[0-9]*([a-z]) ]]."
      echo "  Regex muodostuu useasta regex:stä. Tässä esimerkissä on kolme regex:ää ympäröity kaarisuluilla - huomio että"
      echo "  [0-9] on kaksikin kertaa BASH_REMATCH:in ulkopuolella vaikka kuuluvatkin regex:ään - siis valintajoukkoon ne kuuluvat mutta eivät BASH_REMATCH:iin."
      echo "BASH_REMATCH on koko regex alue= "$BASH_REMATCH
      echo "BASH_REMATCH[1] (elikä regex:än ensimmäisessä ()-osassa olevan regex:n hyväksymä arvo)= ${BASH_REMATCH[1]}"
      echo "BASH_REMATCH[2] (elikä regex:än toisessa      ()-osassa olevan regex:n hyväksymä arvo)= ${BASH_REMATCH[2]}"
      echo "BASH_REMATCH[3] (elikä regex:än kolmannessa   ()-osassa olevan regex:n hyväksymä arvo)= ${BASH_REMATCH[3]}" ;}


kolmas esimerkki, kenttien kääntäminen - vaikkapa Suomalaisen päiväyksen muuttaminen jonkun muun maan esitystapaan sopivaksi:
Koodia: [Valitse]
[[ 1.2.2013 =~ ([0-9]+).([0-9]+).([0-9]+) ]] && echo ${BASH_REMATCH[3]}.${BASH_REMATCH[2]}.${BASH_REMATCH[1]}
- kyse on nopeudesta. Työ olis helpompaa awk:lla tai semmoisilla mutta myös hitaanpaa. Ero on on millisekunneissa mitättömän pieni eikä muiden hitauteen edes vihjata missään - mutta itseasiassa nopeusero on yli kymmenkertainen. 

---

Esimerkiksi matriisien tarkistaminen regex:ällä senvaralta että siinä olisi kirjaimia:
Koodia: [Valitse]
function tarkista_matriisi () { [[ $@ =~ [[:alpha:]] ]] || (( $BASH_REMATCH )) && echo matriisissa ensimmäinen vastaantuleva kirjain:$BASH_REMATCH || echo "matriisisssa ei ole kirjaimia";}; matriisi=({1..100000}); matriisi[5000]=7A7e; time tarkista_matriisi ${matriisi[@]}

- tuo [[:alpha:]] on tässä se regex. Regex:t voivat olla tällaisia pieniäkin mutta esimerkiksi IP6-verkko-osoitteen tarkistamiseen sopiva regex on monen rivin hirviö - mutta silti erittäin nopea.