Yritän tässä määritellä niitä mitä olen kutsunut vanhoiksi käskyiksi sillä eiväthän ne kirjaimellisesti ottaen käskyjä ole vaan dataan lisättäviä ohjeita siitä kuinka data tulisi esittää. Nopeilla käskyillä ei muuten ole matematiikan kanssa mitään tekemistä - silkkaa tekstikäsittelyä ne ovat.
Niiden nopeus tulee siitä että niiden toteuttamiseen tarvitaan vain merkki = tai käsky echo tai jotain senkaltaista nopeaa. Jos pelkästään tuloksia takastellaan niin datan muokkaamiseksi samallatavoin käytetään ohjelmina yleensä sed:iä, pieneltä osin myös awk:ia ja aivan mittömältä osaltaan myös bc:tä - mutta niillä tuloksen saaminen kestää niin kauan ettei niitä käyttäen saisi skripteistä nopeita. Ihmettelin aikanaan kun eräs virtuoosi sanoi että nopeutta haluttaessa pitää unohtaa sed, awk ja bc - täytyy siis olla niin että nopeiden skriptien olemassaolo on tiedetty aina?
Mutta enää en ihmettele sillä nuo vanhat käskyt suorittavat samantapaisia tehtäviä - kylläkin rajoitetummin mutta myös paljon nopeammin. Mutta jokatapauksessa ainoastaan sed, awk ja bc mielletään käyttökelpoisiksi - mikä suureltaosin taitaa johtua siitä etteivät virtuoosit ole koskaan tehneet noista BASH:in nopeista käskyistä minkäänlaista yhteenvetoa - sillä nopeiden käskyjen hyödyllisyys tulee täysin esiin vasta kun melkein kaikki käskyt skriptissä ovat noita vanhoja - sillä tulkki tulkkaa kerralla niitä isonkin joukon eikä tulkkia siis tarvita vähänväliä - joten joskus ne ovatkin parhaita.
Nopeat käskyt ovat vähän niinkuin BASH:in assembleria. Ja vaikka ne ovatkin ylivertaisia suorituskyvyltään niin luultavasti ne on hylätty samasta syystä kuin varsinainen assemblerkin : ohjelman tekeminen ja ylläpito niitä käyttäen on ihan liian kallista - rahallisesti jos skriptin ostaa ja jos skriptin tekee niin selkänahka paukkuu kauan. Virtuooseilla on siis ollut syytäkin tekoseensa - heitä on vaan on niin sopivaa mollata sillä onhan heillä leveät hartiat.
Toki nopeat käskyt toimivat vain niin hyvin kuin moitteettomat käskyt toimivat silloin kolmekymmentä vuotta siten. Esimerkiksi kun etsittävän alku on teksissä eri rivillä kun loppu niin plörinäksi menee. Samoin kirjoitusvirheitä ei suvaita ollenkaan.
***
- lukuja, tekstijonoja, matriiseja tai matriisien yksittäisiä jäseniä voidaan käsitellä 'äärettömän' monin eritavoin - on tosiaan mahdotonta muistaa käsittely-säännöistä pientä osaakaan vaan tiedostoista ne on haettava - eikä missään ole minkäänlaista yhteenvetoa vaan itse se on tehtävä - ja koska yhteenvedon tekeminen on liian suuri työ niin tuloksena on hutilointia ja sotkua - sillä yhteenvedon tekeminen kun olisi isollekin joukolle vaativa tehtävä. Ja nyt yhteenvedon tekeminen on hieman liian myöhäistä sillä ne vanhat käskythän on osin jo unohdettu - joten virtuoosit yrittävät tuhota BASH:in ennenkuin kukaan huomaa?
- nopeat käskyt toimivat vain yhden sanan alueella - mutta lauseesta tulee tavallaan yksi sana kun sen laittaa heittomerkkien väliin - tai myös muuttujalla nimeltään IFS voidaan määrätä sananväliksi merkki jota ei ole käytetty misssään jolloin monirivinenkin teksti tai tiedosto on yksi sana. Jokatapauksessa vanhojen käskyjen käyttämiseen ei tarvita jotakin grep-käskyn kaltaista järkälettä - kuten regex:ät tarvitsevat - joten ne ovat satoja kertoja nopeampia yhden sanan kanssa - tosin ne ovat myös satoja kertoja tehottomampia monirivisten tekstien kanssa sillä IFS:n kanssa leikkiminen on yleensä liian vaarallista - mutta oikeassa paikassa käytettynä ainoastaan nopeus merkitsee.
- BASH:issa jokaista käskyä käsitellään kymmenellä tavalla ennenkuin se lähetetään tulkattavaksi ja päteehän se nopeisiinkin käskyihin. Käsittelyjen suoritusjärjestys on päätetty etukäteen joten kaikki tehdään 'ennen tai jälkeen' monen muun tehtävän joten monet määreet kuten esimerkiksi IFS (= se määrää mikä merkki jakaa sanoja) muuttavat myöhemmin tulevat käsitteyt joskus ihan nurinkurisiksi. Tämmöinen liian suuri monipuolisuus on myös painolasti kielen käytölle - BASH onkin turhan monipuolinen varsinaiseen ohjelmointiin - prottotyyppien tekemiseen BASH on tosin ihan kiva - ja alzheimerin välttelyssä BASH on erinomainen.
- voi olla varma että tästä kuvauksesta on moni merkittävä ominaisuus jäänyt pois sillä BASH:in kirous on se että kaikesta löytyy loppumattomiin uusia ominaisuuksia joten esimerkiksi kaikki käsikirjat ovat kelvottoman isoja tiiliskiven kokoisia raamattuja - esimerkiksi pääte-ohjelman käsikirja vaatisi viikkojen opiskelun ennenkuin homma olisi hanskassa - ja silti useimmat meistä käytävät päätettä käsikirjaa lukematta ja hyvin se sujuu niinkin - toiminta on silloin tosin joskus hidasta ja ärsyttävää mutta kaikki toimii kyllä jotenkin.
Jospa joskus tajuaisin päivittää tätäkin kuvausta - tai sitten ei, jottei tästäkin tulisi tiiliskiveä - sillä tiiliskiveä ei lue kukaan.
BASH on ainakin mielenkiintoista moniulotteista shakkia eikä hölmöilystäkään tule paineita - sillä onhan BASH siinä itsekin ihan omaa luokkaansa. Mutta jos saisi kirjastojen käyttämisen palautettua niin kuka tietää mitä BASH:ista tulisi.
***
Usein isoilla ja hitailla skripteillä on nopeat korvaajat - muihin kieliin verrattuna BASH on tosin hidas sittenkin. Koska ne on aikaisemmin tunnettu niin miksi ne on hylätty? Sillä ne ovat nopeampia, lyhyempiä ja ainakin tuntuvat vakaammiltakin.
Ehkäpä paras keino kuvata noita nopeita käskyjä on muutama esimerkki toimivista ohje-tyypeistä. Kaikki toimivat niin monella eritavalla ettei esimerkkejä kaikista voi antaa:
- tehtävä1: jaa annettu sana jonkun merkin kohdalta ja esitä joko etu- tai jälkiosa. Jakopiste voi olla myös sana - siis myöhemmin tehty uusissa käskyisä oleva 'parempi' cut-käsky joka jakaa vain yksittäisen merkkin ollessa jakopisteenä on varsinainen möhläys. Jakava merkki voi olla sanassa ensimmäinen jakavan merkin kaltainen tai sitten viimeinen. Jakava merkki voidaan esittää myös merkkiluokan osana, esimerkiksi: [1-9] -> siis nollan kohdalla ei tehdä mitään.
Esimerkiksi: desimaaliosa=${luku##*.} . Tai voidaan kirjoittaa pisteen sijaan: [.,] jolloin desimaalipisteenä voi olla joko piste tai pilkku - nopeudessa tuommoiset pikkujutut eivät tunnu vaikka niitä olisi montakin.
- tehtävä2: tuhoa, muuta tai tulosta sanasta jotakin määriteltävien ominaisuuksien perusteella. Esimerkiksi kun tekstijonona esitetystä desimaailuvusta pitäisi tehdä 'silmälle miellyttävä': poista kokonaisosasta etunollat ja desimaaaliosasta takanollat ja desimaalipistekin jos se jää viimeiseksi - eikä muihin nolliin saa kajota:
luku=${luku##+(0)}; [[ ${luku//[^.]/} ]] && luku=${luku%%+(0)}; echo ${luku%.}
Tällainenkin toiminta voidaan toteuttaa merkkiluokkien avulla - merkkiluokka on esimerkiksi: [0-9] elikä numroiden luokka - tai onhan noita: [:alnum:], [:alpha:], [:blank:], [:cntrl:], [:digit:], [:graph:], [:lower:], [:print:], [:punct:], [:space:], [:upper:] ja [:xdigit:] - tai jotain muuta hakasulkujen välissä olevaa määritystä - kaksois-sulkuja kulemma kannattaa käyttää.
- tehtävä3. muuta joku sana/sanaryhmä jossain tiedostossa. Muutettavien sanojen ei tarvitse olla yhtäpitkiä - voit siis vaikka tuhota määrättävän sanan koko tiedostossa. Muutettavassa sanassa saa olla välilyöntejäkin. Muutettavia saa olla montakin samalla rivillä.
mika=BEGIN; miksi=ALOITA; < /boot/grub/grub.cfg readarray doku; printf "%s" "${doku[@]//"$mika"/"$miksi"}" | tee ~/poista_luettuasi
tulos ilmestyy näytölle ja myös kotikansion tiedostoon: ~/poista_luettuasi. Mitään ei varsinaisesti editoida - vaaraton esimerkki tämä on.
- tehtävä4: määrittele missä kohtaa annettavassa pitkässä sanassa on jokin kirjain/kirjainryhmä (= pos-funktio). Sekä etsittävässä ettäetsijässä saa olla välilyöntejä. Esimerkki:
isosana="Pitkät on puut Pisan mäellä, hongat Hornankalliolla"; pikkusana="Pisan m"; [[ "$isosana" =~ "$pikkusana" ]] && { echo -n 'pikkusana alkaa kohdalla:'; apu=${isosana%%$pikkusana*}; echo $((${#apu}+1)) ;} || echo 'pikkusanaa ei löydy'
- tästä olisi helppoa tehdä versio joka ilmoittaa kaikki ne paikat joista etsittävä löytyy.
- onko ihme että BASH:ia väheksytään kun tämöisistä super-nopeista ja vakaista on siirrytty epävakaisiin aikasyöppöihin?
tehtävä5: yhdistä kaksi edellistä grep-käskyn kaltaiseksi - siis tarkoituksena on käydä nimettävä tiedosto läpi ja jokaiselta riviltä miltä esittävä löytyy tulostetaan rivinumero ja löytökohta:
function grep2 () { < $2 readarray doku; rivino=0; for n in "${doku[@]}"; do rivino=$(($rivino+1)); apu=${n%%$1*}; [[ "$n" =~ "$1" ]] && { echo -n 'haettava löytyi riviltä: '$rivino' paikalta:'$((${#apu}+1)); echo ;} ; done ;}; grep2 "feature is" /boot/grub/grub.cfg
- siis kutsu on kokonaisuudessaan: grep2 mikä_ilmaisu mistä_tiedostosta. Sanassa mikä_ilmaisu saa olla välilyöntejä mikäli se laitetaan heittomerkkien väliin. Alkuperäinen grep ei edes salli heittomerkkejä ja ilman niitä se toimii hitaasti ja väärin.
- tämä on kolme kertaa hitaampi kuin alkuperäinen grep - mutta paljon nopeampi kuin BASH-skripti tavanomaisilla uusilla käskyillä. Silloin aikoinaan tällaisilla olisi hyvin voinut kilpailla grep-käskyn kanssa. Lisäksi tämän saa muokattua aivan sellaiseksi kuin käyttäjä haluaa.
- näistä nopeista käskyistä muodostetut skriptit lisäksi senjälkeenkun sen toimivat osat on koottu joko toimivat tai sitten ei - mutta sitä uusien käskyjen raivostuttavaa taipumusta ei ole että alkuunsa saa virheellisiä tuloksia kunnes korjattuaan skiptiä miljoona kertaa alkaa saada oikeita tuloksia yhä useammin. Ovatko uudet käskyt siis paitsi satoja kertoja hitaampia niin myös loogisia pommeja?