juuli 09, 2015

Regulaaravaldised ja grep II

Laiendatud GREP ehk GREP -E


Kui iganes vajate regulaaravaldisi, kasutage kohe
grep -E ... varianti.
Teisiti öeldes kasutage laiendatud regulaaravaldisi,mis ei olegi edasijõudnule nii väga laiendatud.
Siis võib proovida grep -P (perli standard). Kui juba niikaugel ollakse, oleks päris mõistlik pärast seda selgeks õppida ka programmeerimiskeel Perl ja kasutada selle asemel Perli sisseehitatud regulaaravaldiste süsteemi.
Aga pidagem meeles Zawinski mõrudat aforismi - ühe regulaaravaldiste süsteemi puhul on teil vaid 2 probleemi, kui aga kasutate mitut regulaaravaldiste süsteemi ühteaegu, kasvab probleemide arv veelgi. Parem siis kohe enam-vähem korralik regex.

MIS EI OLE REGULAARAVALDIS

Unixi failide otsimise mustrid ei ole regulaaravaldised, üleüldse kõik, mis käib termini globbing alla. globbing tulenes Unixi omaaegsest kombest enne „õigele” käsule andmete üleandmist failide loetelu laiendada. Seda tegi käsk /etc/glob.
Ka praegu teeb seda funktsioon glob() ja teeb mõne kesta skripti käitumise päris ettearvamatuks.
Et globbingu eest pääseda, tuleb unixi kestas kirjutada kõik tekstid ühekordsete ülakomade sisse. Kahekordsete puhul saab sõnedest argumentide sisse smugeldada „keskkonnamuutujad”.

PERLI REGULAARAVALDISED

ei ole ka päris regulaaravaldised, sest Kleene algebra neid võimalusi ei kasuta, mis Perli regulaaravaldistes sees on. Nii on päris hea alustada või lähtuda „laiendatud regulaaravaldistest”, mis tegelikult vastab päris hästi Kleene poolt kirjeldatud regulaarsetele hulkadele ja teeb ikkagi natuke rohkem.

Unustame nüüd teoreetilise tarkuse ja asume asja juurde.

Katsun asju esitada probleem - lahendus stiilis.

I Kuidas teostada literaalset otsingut kirjavahemärkidega teksti puhul.

Ülesanne: Kirjutada grep -E käsurida, nii et literaalselt, s.t. täht-tähelt otsiks see teksti seest stringi
!"#%&_,/:;=@+*().?-[\]$^{|}'<>


Oma töö kontrolliks looge fail kirjavahemargid ja pasteerige sinna tekst

Arno kirjutas krihvliga tahvlile:

Kirjavahemärgid arvutiasjanduses on sellised !"#%&_,/:;=@+*().?-[\]$^{|}'<>

ja neid on veel ja veel, aga need on kõige kasutatavad



Käsureal saab katsetada oma otsinguid järgmiselt, olgu hakatuseks võetud regulaaravaldis '!”#'
grep -E -e '!”#' kirjavahemargid
Kui saate kirjavahemärkidega rea failist kätte, võib proovida käsuritta uusi kirjavahemärke lisada ja jälle testida.
See meetod on hea ka edaspidi.
Ära usalda aga kontrolli nii manuaale aga ka oma arusaamist regulaaravaldistest.
Õnneks läheb literaalse vastavuse otsing ludinal kuni + märgini. Siis aga algavad erimärgid, need on laiendatud regulaaravaldiste puhul sellised:
+*().?-[\]$^{|}
Ülakoma märk ei ole erimärk, aga lõpetab egrepi / grep -E stringi/sõne ja ja ka seda peab eraldi kohtlema, alustades kohe uut sõnet (vt. allpool). '><' märgid ka ei ole erisümbolid, aga langujoon annab neile eritähenduse, seetõttu ma panin nad ka siia ritta.



Erimärkide erikohtlemine regulaaravaldistes

Regulaaravaldistes kohtab kahte tüüpi metasümboleid:
* ühesümbolilised erimärgid +*().?-[\]$^{|}
* Escape ehk paosümboli '\' järel tulevate jadade abil moodustatud metasümbolid / käsud.
Paosümbolit '\' kasutatakse ka metasümbolitelt eritähenduse eemaldamiseks.
'\*' tähistab regulaaravaldist, mis otsib teksti seest * märgi esinemist.
Nii on ka kõikide teiste ülaltoodud metasümbolitega, kaasa arvatud langujoon ise:
'\\' esitab literaalselt langujoont regulaaravaldises.
Kui aga sümbolil endal ei ole metatähendust, võib ta selle omandada, kui selle ette kirjutada langujoon.
Egrepis on selliselt vermunud metasümboleiks
\b ,\B, \w,\W ja \< ja \>.
\b on sõnapiire, \B mittesõnapiire, \w tähistab sümbolit, mis võib kuuluda sõnasse (nii nagu regex sellest parajasti aru saab) , \W on sümbol, mis ei kuulu sõnasse.
\< on sõna alguse piire, \> tähistab sõna lõpupiiret.



Niisiis on kuni ülakomani metasümbolite literaalse esituse probleem lahendatud:
grep -E -e '!"#%&_,/:;=@\+\*\(\)\.\?\-\[\\\]\$\^\{\|\}' kirjavahemargid
Ülakoma literaalse sisestamise jaoks tuleb sõne lõpetada ' -ga, kesta bash pääsusümboliks oleva '\' abil sisse smugeldada üks ülakoma
ning lisada märgid '<' ja '>' juba uuete ülakomade vahel.
grep -E -e '!"#%&_,/:;=@\+\*\(\)\.\?\-\[\\\]\$\^\{\|\}'\''<>' kirjavahemargid
Sama jama saab ära teha plokk-escape sümbolitega \Q ja \E Perli grepis:
grep -P -e '\Q!"#%&_,/:;=@+*().?-[\]$^{|}\E' kirjavahemargid



II Kuidas kirja panna korralikus regulaaravaldise keeles Windows / bash stiilis otsinguid?
Oletame, et otsime faili nimega „Kui Arno isaga koolimajja jõudis”.
Kuidas seda kiirelt teha? Unix bashis leiab selle kiiresti
ls Kui*isaga* abiga.
cp kevade 'Kui Arno isaga koolimajja jõudis'
ls Kui*isaga*
Tekstifailist kevade aga sellise regulaaravaldise mustri abil te ei leia mitte midagi. Proovige!
grep -E -e 'Kui*isaga*' kevade
Või otsing 'Arn?'
cp kevade Arno
ls Arn?
töötab, aga
grep -E -e 'Arn?' tegelikult petab meid, sest annab välja read, kus sisaldub Ar või Arn, see pole üldsegi sama otsing.
Vastus algab erisümbolist punkt '.'
Küsimärgi asemel on regulaaravaldises PUNKT. Nii lihtne see ongi!
Punkt klapib iga sümboliga. Otsing
grep -E -e 'Arn.' kevade on samaväärne tehe kevade tekstifaili suhtes, mis bashis Arno nimelist faili taga ajada - ls Arn?
'*' -l on eristaatus regulaaravaldiste maailmas. See tähistab tehet „null või enam korda”,
rakendatuna tärnile eelnevale sümbolile, VÕI eelnevale alam-regulaaravaldisele, mis peab sel juhul olema sulgudesse eraldatud.
Näiteks ab(ab)* tähistab nüüd seda, et ab asemel klapib otsingutega ka sümboljada
abab, abababa... ja nii edasi ....
Kui seda rakendada PUNKTILE, saame igasuguse sümbolite jada.
'.*' tähistab suvalist sümbolite jada.
Teisiti öelduna peaks bashi otsingu ekvivalendina * asemele kirjutama '.*'
Järelikult failiotsingu ls Kui*isaga* ekvivalendiks failist kevade oleks
grep -E -e 'Kui.*isaga.*' kevade.
Tehtemärki * nimetakse Stephen Kleene auks veel „Kleene'i tärniks/täheks” (Kleene star).
Kas 0 tõi täpselt 1 kord:
'?' tähistab aga Kleene maailmas valikut - eelneva sümboli / alamavaldise esinemist 0 või 1 kord.
Nii klapib avaldis 'Arn?o' nii sõnedega 'Aro' kui ka 'Arno' ...
III Kas Arno või Teele?
Täiendame Kevadet omade lausetega. Kirjutame sinna ka rea „Kui Teele isaga koolimajja jõudis, ei olnud koolipäev veel alanudki ...”.
olgu see shedööver kirjas failis kevade3.
sed '1 a Kui Teele isaga koolimajja jõudis, ei olnud koolipäev veel alanudki' kevade >kevade3
sed - stream editor selle käsuga lisab reale 1 täiendava rea ja väljund jõuab faili kevade3.
Nüüd
grep -E -e 'Kui (Arno|Teele)' kevade3
trükib välja mõlemad read, sest '|' on alterneerimise tehte sümbol, võimaldades OR valikut
erinevate alammustrite vahel, praegu siis Arno või Teele.
Sulgude puudumisel oleksid alammustrid 'Kui Arno' või 'Teele'.
Võite kontrollide - kustutage (juba editoriga) 'Kui' Teelega seotud realt ära ja proovige mustreid sulgudega ja ilma.
IV Süntaktilise suhkrutõve algus: avaldised parooli kõvaduse testimiseks.
Eespooltoodud konstruktsioonidega saavad matemaatikud hakkama - kõik Kleene mõttes regulaarsed avaldised on nii konstrueeritavad ja kasutatavad. Aga mõned avaldised lähevad kole pikaks.
Olgu meil näiteks vaja välja otsida read, mis sisaldavad vähemalt ÜHE avaldise abc, aga võib-olla
rohkem. Selleks tuleb abc välja kirjutada 2 korda:
'abc(abc)*'
Või olgu meil vaja kontrollida, sisaldab see rida abc-d 4-8 korda.
'abcabcabcabc(abc)?(abc)?(abc)?(abc)?'
Esimese variandi jaoks on leiutatud operaator '+', mis temale eelneva sümboli / alammustri puhul seab nõudeks ekisteerida vähemalt 1 kord.
nii et '(abc)+' 'abc(abc)*' asemel.
Teise variandi puhul kasutatakse kvantoreid {m,n}
See avaldis tähistab temale eelneva sümboli / alamavaldise esinemist vähemalt m korda ja maksimaalselt n korda.
{m,} tähistab avaldise esinemist m ja enam korda
{m} täpselt m korda.
Pika
abcabcabcabc(abc)?(abc)?(abc)?(abc)?'
asendab '(abc){4,8}'
Kõiki sarnaseid mugandusi, mis võimalusi juurde ei loo, nimetatakse süntaktiliseks suhkruks ja esialgu on sellega kõik OK. Kuid kõik mist algab hästi, lõpeb halvasti, ütleb Murphy ja nii on siingi läinud.
Te näete peagi, et suhkrust saab peatselt sool, kuna regulaaravalduste süntaks PERL standardis on võrdlemisi keeruline ja võimalusi muudkui lisandub...
Kindlasti vajalikud aga on TÄHEKLASSID.
Olgu meil näiteks alterneerimise sümboli abiga vaja kirja panna avaldis 3 kohalise täisarvu tuvastamiseks.
Saaksime midagi sellist:
'(1|2|3|4|5|6|7|8|9)(0|1|2|3|4|5|6|7|8|9){2}'
Ühe sümboli valikuks on loodud nurksulgudes sisestavad täheklassid.
kolmekohaline täisarv oleks siis selline:
'[1-9][0-9]{2}'
Nurksulgude sees on erisümboli tähendus langujoonel '\', katusel ^, sidekriipsul -, ülejäänud sümbolid kaotavad oma väe nurksulgude sees.
Sidekriips mitte esimeses positsioonis tähistab vahemikku. Esimeses positsioonis kohe esimese nurksulu järel on ta tavaline sidekriips.
Näiteid vahemikest:
[1-9] - numbrimärgid vahemikust 1...9.
[a-z] - inglise tähestiku väiketähed kindlalt ning korrektsete regionaalsete /jms. valikute korral ka täpitähed....



A-Z tähistavad siis suurtähti.
Ikkagi tuleks langujoon, sidekriips ja katus märgistada langujoonega, parem lugeda, isegi siis, kui sidekriips on esimeses positsioonis, kus ta vahemikku ei saa kuidagi tähistada.
Katus tähistab eitust esimeses positsioonis.Nii et [^0-9] võiks tähistada mitte numbrimärki.
Isegi „laiendatud regulaaravaldiste” kitsas võimaluste ruumis on [] vahel kasutusel kindlad täheklassid, kasutage neid alati näiteks [0-9] asemel.
{Perl - ühilduvas regulaaravaldistes on nende asemel alati võimalik kasutada \d stiilis sümboleid,
\d tähistab siin numbrit (digit).
}
Need on
[:alnum:] - tähed ja numbrid, \w on sama, mis [:alnum:], \W sama, mis [^.[:alnum:]], btw, täheklasse saab ka eitada katuse sümboli abil...
[:alpha:] - tähed
[:cntrl:] - kontrollsümbolid
[:digit:] - numbrid
[:graph:] - graafilised sümbolid
[:lower:] - väiketähed
[:print:] - prinditavad sümbolid
[:punct:] - kirjavahemärgid
[:space:] - „tühi ruum
[:upper:] - Suured tähed
[:xdigit:] - heksadetsimaalne arv.
Paneme lõpuks kirja ka käsu, mis kontrolliks põhimõtteliselt, kas paroolifailis sisalduvad paroolid
sisaldavad vähemalt ühte suurtähte, väiketähte, numbrit ning on vähemalt 6 sümbolit pikk:
pikkus: '.{6,}'
üks suurtäht: '[[:upper:]]'
üks väiketäht: '[[:lower:]]'
üks number: '[[:digit:]]'



grep -E -e '.{6,}' parool | grep -E -e '[[:upper:]]' | grep -E -e '[[:lower:]]' | grep -E -e '[[:digit:]]'
Et neid nõudeid kontrollida, tuleks regulaaravadliste klapikontrolli mitu korda sõltumatult rakendada. Praegu saab selleks kasutada Unixi „torusid”.
Sarnasel viisil võib kontrollida ka seda, kas kevade faili mingi rida sisaldab korraga sõnu „Arno” ja „isaga” etc.. sõltumata sõnade järjekorrast. See oleks üks võimalus teha AND operatsiooni sõnade tuvastamisel ridades.
Pisut mugavamalt saab mitme tingimuse üheaegset kontrolli teha Perli greppi kasutades ning edasivaate või tagasivaate ankruid rakendades. Sellest edaspidi.
V Ankrud:
Ülesanne: Lugeda üle mingi projekti seest kõik koodiread, jättes välja tühjad read ja kommentaarid.
Sageli on vaja otsida tekstidest asju, mille paiknemine on teada - kas rea algus või rea lõpp.
Mõnikord on vaja otsida ka faili algusest või lõpust.
Oleme jõudnud nüüd kohta, kus projektijuht tahab lihtsalt ridade ülelugemise asemel (arendajad võivad olla kavalad ja lisada palju tühje ridu või ka tühje kommentaare stiilis // hei see on kommentaar) teada saada, palju ka tegelikult tööd tehakse.
Selleks on välja mõeldud ankrud / anchors.
Rea alguse ankruks on „katuse” sümbol
'^'.
Kõik read, mis algavad sõnaga 'Kui' saab kevade-st kätte käsuga
grep -E -e '^Kui' kevade
Rea lõpu ankruks on dollari märk.
Kõik read, mis lõpevad sõnaga 'alanud' ning lisaks ka kirjavahemärgid / tühikud, annab välja
grep -E -e 'alanud\W*$' kevade
Nüüd saab hakata lahendama koodiridade lugemise programmi probleemi. Teen seda C keele jaoks,
teiste keelte puhul on vajalik muuta ära koodi märkimiseks kasutatavad laiendid ja kommenteerimise reeglid.
Lisaksin, et ei ole mõtet ragistada ajusid vähemalt c keele puhul väga range lahendi jaoks.
Kui see keel tekkis, ei olnud see reapõhine, ühte ritta armastati kirjutada mitut käsku korraga ja oldi koguni uhked selle üle. Isegi sinna kuhugi vahele võis poetada mõne lühida, aga ülitäpse remargi. Ka rea lõppu võis ja võib kirjutada kommentaari.
Aga unixi enda filtrid olid kõik reapõhised.
See pxxxo on hakanud natukene hajuma, koodinikerdajad ise on avastanud, et võiks olla mingid vahendid, mis näiteks nende targad mõtted koodiridade vahelt jälle üles otsivad, tekitades automaatse dokumentatsiooni mulje.
Seetõttu tegin järgmised eeldused kommentaaride suhtes:
a) kommentaarid on reapõhised. Kas mingi rida on kommentaar või ei ole.
b) // -ga algav rida on kommentaar
c) /* märk rea alguses annab märku, et järgnevad read on kommentaarid, aga need on kuidagi eraldi ära märgitud. Näiteks c-s on traditsiooniline märk selleks *, seega * -ga algavad read olgu ka kommentaarid.
{Tegelikult ei ole, aga väga jabur on kirjutada koodi, kus rida alustada *-ga.}
d) */ märk rea ALGUSES lõpetab kommentaari. Ehk kusagil mujal ka, aga siis on tegemist üherealise kommentaariga stiilis ; /* hallo sallo */ ja seda koodirida ei tahaks arvestamata jätta.
e) kõik muu on kas kood või mingisugune kräpp, näiteks väljakommenteeritud kood.
Ka väljakommenteeritud kood on kood ja selle eest peab boss raha maksma.
Aluseks võtame juba väljamõeldud rea, mis õnnetuseks tühjad read ja kommentaarid ka tööks luges -
grep -Erch --include='*.c' --include='*.h' '' . | awk '{ sum += $1 } END { print sum }'

grep -le on vaja lisada
a) -v ja eemaldada '', loeme üle read stiilis kõik, mis ei ole kräpp
b) '^$' on tühja rea lugemiseks.
c) '^//' loeb reapõhiseid kommentaare
d) '^\*' neid ridu, mis on /* ja */ ridade vahel.
e) '^/\*' pika kommentaari algusrea märk
f) '^\*/' pika kommentaari lõpurida
Tulem:
grep -Erchv --include='*.c' --include='*.h' -e '^$' -e '^//' -e '^\*' -e '^/\*' -e '^\*/' . \
| awk '{ sum += $1 } END { print sum }'

Nonii. Vähemalt 10% arendajate palgast saab nüüd paremateks otstarveteks kasutada...



VI Piirded / Boundaries
Ülesanne: Lugeda ära „Kevade”-s / „Talve” -s sisalduvad sõnad ja nende sagedused ja püüda nende põhjal hinnata, kas Luts võis olla kirjutanud „Talve”.



Märkus:
See ülesanne on virtuaalne, ma ei kavatsegi seda lahendama hakata. Küll loeks hakatuseks meeleldi ära kõik sõnad minu juba sissetipitud lõigukesest „Kevade” alguses ja nende sageduse / arvu. Enamasti on see 1 või 2, seetõttu mingeidki järeldusi kirjutaja kohta vaevalt et annab teha.
Selle ülesande lahendamiseks tuleks tekstist välja eraldada sõnad. Ridade eraldajatega me juba tegelesime, rea alguse ja lõpu märkijaid võib ka eraldajateks lugeda.
Nüüd tegeleme sõnaeraldajatega.
Mõlemal juhul ei ole tegemist reaalsete sümbolitega, vaid teatud mõtteliste punktidega sümbolite vahel.

Katus ja dollar on rea alguse ja lõpu markerid, '\<' ja '\>' sõna alguse ja lõpu markerid.
Perlist on üle võetud sümbol
'\b', mis võib märkida nii sõna algust kui sõna lõppu.
Neid markereid teades on ülesanne üsna triviaalne.

Keda ei huvita ajalugu, minge loo lõppu, leiate sealt lahenduse.
Literaalne programmeerimine ja Unix
Kasutan siin juhust ja kirjeldan selle ülesandega seotuna ka kahe titaani, Donald Knuthi ja McIlroy vaidlust programmeerimise filosoofiate üle.
vt. http://www.leancrew.com/all-this/2011/12/more-shell-less-egg/
Enne vaidluse juurde asumist: ma olen süüdimatu oportunist, toetan kõike, mis töötab. Tähtis on, et programmid oleksid töötavad ja neist aru saadaks, ka seda ikkagi selleks, et nad ka edaspidi hästi töötaksid. Tähtis on, et kassid hiiri püüaksid.



Donald Knuth mõtles vaidluse ajal välja stiili, mida ta ise nimetas „kirjanduslikuks/literaalseks programmeerimiseks”. Teadvalt kasutas ta kahetähenduslikku sõna „literate” ning „kirjanduslik programmeerimine” on siiski jäänud huvitavaks, vahest ka arendavaks ideeks arvutiteaduses, mida ikka ja jälle üles korjatakse.
Minu arusaamise järgi oli ideeks hoida koos koodi ja koodi dokumentatsiooni, kirjutades mõlemad ühte dokumenti kokku. Koodi genereerimiseks tuli kasutada omaette makrode süsteemi, dokumentatsiooni genereerimiseks omaette makrode süsteemi,
kuigi vist peamiseks dokumendiks oli see literaalne programm ise, mis valmis nikerdatud? Jätan selle küsimuse lahtiseks. Äkki mõni arvutiteaduse instituudi doktorant lahendab selle ära?
Kood ise pidi pigem peegeldama kirjutaja mõtteid ja kavatsusi, mitte olema kompileerimise jaoks kokku pandud.
Edasi võite lugeda sellest ise Donald Knuthi teoseid uurides.
Probleem on selles, et sarnaseid mõtteid on väljendatud ikka ja jälle, erinevates kontekstides. Ja probleem on selles, et endiselt, 25 / 30 või 50 aastat hiljem ikkagi selgub, et kood on natukene erinev asi, kui koodi kirjeldav dokumentatsioon. Kui need kaks asja oleksid piisavalt lähedased, püsiksid programmid töötavatena koos kogu elutsükli vältel.
Äkki on veerandsada aastat „Literaalse programeerimise” algusest piisav aeg, et näha, et kokku nad ei saa küll kunagi, aga nad võivad muutuda lähedasteks, nagu Koit ja Hämarik.
Arvutiteaduse suvekoolide valgete ööde ajal võib see unistus ise
gi teatud määral täituda.
Niisiis kirjutas Knuth valmis 10 + leheküljelise programmi oma literaalse programmeerimise keskkonnas WEB. Mitte just palju, mitte aga väga vähe selle ülesande jaoks.
Seejärel McIlroy kiitis koodi väärtusi, aga seejärel lühidalt esitas OMA 6 realise lahenduse kirjeldatud probleemile, mõõta sõnade esinemissagedusi. Eesti keeles nii ehk teisiti tuleks kõvasti, rohkem vaeva näha, sest meie sõnad käänamisel tikuvad väga muutuma. Ikka need 14 käänet omastav,osastav, sisseütlev, seesütlev, seestütlev, alaltütlev, alalütlev, alaleütlev ja ninataga käänded otsa veel ...
Ma kopeerin ja pasteerin selle lahenduse kõigepealt siia,
surun ühele reale, jättes lõpuväljastuse (N popimat sõna välja trükkida, selle asemel trükin kõik, sest lõik oli niivõrd lühike), kirjutan ühe rea üle grepina, et õigustada selle esinemist siin.
Ja mõelgem edasi, kas probleemi lahendamiseks on sobivam 6 või 600 rida.
Originaalne McIlroy programm:

tr -cs A-Za-z '\n' | // asenda sõnavahed reavahetustega
tr A-Z a-z | // teisenda suurtähed väiketähtedeks
sort | // järjesta, et ühesugused sõnad oleksid järjest uniq -c jaoks
uniq -c | // kõrvalda samasugused read, kirjutada iga sõna juurde esinemissagedus
sort -rn | // sorteeri NUMBRILISE väärtuse järgi
sed ${1}q // trüki välja parameetrina antud arv ridasid, see rida jäetud minu poolt välja sõnade väikse arvu tõttu.


tulemus ühel real, võtta failist kevade:

tr -cs A-Za-z '\n' | tr A-Z a-z |sort |uniq -c |sort -rn



Toimiv rida, mis etteantud tekstifaili sõnad üle loeb ja ritta paneb:

tr A-Z a-z <kevade | grep -o -E -e '\b\w*\b' | sort | uniq -c | sort -rn

Märkus - sellest McIlroy programmireast esimene käsk ei toiminud hästi, täpitähed loobiti lihtsalt välja. Ümberkirjutus grepile aga toimis ja pikemate tekstide puhul toimiks ka suunamine sed-i.
Kogu ilu siin aga peitus regulaarses avaldises '\b\w*\b' ...


VII Tagasiviited ja regulaaravaldised

Ülesanne: Kirjutada kesta skriptina ühereakas (onliner) prime,

kasutades greppi ja regulaaravaldisi. Kui parameetrina anda ette arv, näiteks 17, siis

vastus on kas 1 (kui on tegemist algarvuga, 17 puhul ) või 0, kui ei ole algarvuga tegemist (20).
Vastus:
printf '1%0.s' $(seq 1 $1) | grep -E -vc -e '^(11+)\1+$'
Kopeerige see rida faili prime.
K
es teab, võib lisada ka sha bangi, kes ei tea, ei ole vaja.
chmod +x prime on aga vajalik. Skript käivitada Linuxis oma kataloogis olles, kasutage ./prime
(see on meenutus neile, kes on eluaeg windowsi stiiliga harjunud, k.a. allakirjutanu)



Enne kui asuda tagasiviidete vaatlemise juurde (mis EI OLE Kleene kavatsustes kunagi olnud), märgin, et printf ülesandeks on vaid prime -le parameetrina antud arvu pikkuse rea genereerimine, kasutades ühtesid.


'^(11+)\1+$'

klapib iga kordarvuga. grep pöörab vastuse 1-ks / või 0-ks, kui regulaaravaldises on klapp.
võtmete -vc abil.
\1 tähistab regulaaravaldistes tagasiviidet. Kui eraldi ei ole märgitud, siis laiendatud regulaaravaldiste mootorid jätavad meelde (või võime eeldada, et jätavad) sulgudes ära märgitud alamavaldised ning vastavalt sulgude järjekorrale tähistavad need \1, \2 ... \N -ga.
Praegu on meil vaid üks tagasiviide, mida tähistab \1.


Nimetatud tingimusele vastav sõne saab sisaldada vaid kordarv 1-sid ühes reas.
Kui sulgavaldiseks on 11, siis siit seeriast saame klappivateks avaldisteks 11, 1111, 111111..
ehk kõik paarisarvuliste 1-de arvuga read.
Kui sulgavaldiseks on 111, saame kõik 3 kordsete ühtede arvuga read.
Millega aga kuidagi klappi ei ole võimalik leida, on algarvulise arvuga 1-de read.
Kahjuks nimetatud skript ei ole väga arvutusvõimeline, minu linuxil hangus ta peaaegu juba viiekümnerealise ühtedejoru vaatlemisel.
Asja parandab aga oluliselt PERL-ühilduva regulaaravaldise kasutuselevõtt - asendage
(11+) saladusliku (11+?) -ga ja asendage grepi võti '-E' '-P' -ga (perli regulaaravaldistest arusaav grepp).


ÕIGE VASTUS:


printf '1%0.s' $(seq 1 $1) | grep -P -vc -e '^(11+?)\1+$'




IX:Sissejuhatus perli GREPPi:
Taluperemees Juhan pidas tekstifailis inventuuri oma loomade üle. Kirjed olid formaadis
NN lammast NNN lehma MMM siga ... ning edaspidi ei märkinud külamees enam oma faili koguarvu, vaid ainult juurdetulnud - mahaläinud loomi.
Kirjutada regulaaravaldised, mis sellisest failist tulemused aitaks kokku võtta.
näidisfail loomad
5 lammast
4 siga
6 jänest
5 lammast
1 lammas; -1 lammas (suri ära)
2 jänest; 3 jänest;
...
Lõpus veel järgmised kirjed:
lambaid 3
jäneseid -4
jäneseid 3
Ühel ilusal päeval ütles ta poeg Jukule, et ole hea ja liida arvutis need kokku. Juku käis õnneks ülikoolis ja ta sai kerge vaevaga hakkama kõikide koduloomade kokkuliitmisega, kasutades perli regulaaravaldisi ja awki ning pärast kõva pusimist oskas eraldi välja arvutada ka jäneste, lammaste ja sigade koguarvu.
Lahenduse algus tundub lihtne - vajalik oleks kasutada grep -Po -d ning suunata see meile juba hästi tuntud awk ühereakasse

awk '{ sum += $1 } END { print sum }'

Kõikide farmis elajate elajate koguarvu saab nii lihtsalt:
grep -Po -e "-?\d+" loomad | awk '{ sum += $1 } END { print sum }'

Märgime, et '-?\d*' tähistab negatiivset või positiivset täisarvu, \d on Perli grepis numbrimärgi tähis,
\D tähistab mittenumbrit.
Kuidas aga eraldada „sikud lammastest”, eriti kui mõnikord lammas on eespool numbrimärke ja mõnikord tagapool?
Ilmselt on vaja mingeid töövahendeid, et otsida arve, mille järel tuleb sõne „lammas”
või mille ees on sõne lambaid. Nende ja paljude teiste uute vahendite jaoks leiutas Larry Wall süntaksi '(?...) '
Sellest ning üleüldse küsimärgist on saanud regulaaravaldiste süntaktiline „sool”, üsna raskesti loetav ja desifreeritav sümbolijoru. Pealekauba teostavad sarnaselt väljanägevad käsud väga erinevaid asju.
Ümbervaatamise ankrud / eeldused (lookaround anchors) /assertions
Ettevaatavad ankrud /Lookahed anchors
(?=...) - positiivne ettevaatlus / positive lookahead assertion
(?!...) - negatiivne ettevaatlus / negative lookahead assertion
Tagasivaatavad ankrud /Lookbehind anchors
(?<=...) - positiivne tagasivaatlus
(?<!....) - negatiivne tagasivaatlus.
TAGASIVIITEID saab ankrute külge ka panna, selleks ümbritsega sulgude sees kasutatav regulaaravaldis uute sulgudega.
Nagu öeldakse, ümbervaatamise operatsioon ise ei salvesta regulaaravaldist, mis ümbervaaatluse operaatori taga on, see ei ole „capturing” expression.
Lambaid saab 'loomad' failist lugeda niimoodi:
grep -Po -e '-?\d+(?= lammas)|(?<=lambaid )-?\d+' loomad | awk '{ sum += $1 } END { print sum }'
saame 13 lammast
Analoogia põhjal jäneseid:
grep -Po -e '-?\d+(?= jänes)|(?<=jäneseid )-?\d+' loomad | awk '{ sum += $1 } END { print sum }'
vastus 10 jänest
grep -Po -e '-?\d+(?= siga)' loomad | awk '{ sum += $1 } END { print sum }'



annab 4 siga.


Siin ma praegu lõpetan, sest grep -P ei ole pikemas perspektiivis korralik töövahend perl ühilduvate regulaaravaldiste uurimisel. Piirduge grepi puhul grep -E võimalustega ja edasise arengu huvides omandage programmeerimiskeel perl.
Kogunenud bibliograafia:
1. Jeffrey Friedl „Mastering regular expressions”
http://regex.info
Peab olema number üks igasugueid regulaaravaldisi käsitlevas bibliograafias.
2. Jan Goyvaerts Regular-Expressions-Cookbook
http://www.amazon.com/Regular-Expressions-Cookbook-Jan-Goyvaerts/dp/1449319432
3. Rex Egg - meeldejääv, pühendumusega valminud netisait regulaarseist avaldistest
http://www.rexegg.com/
4. http://www.regular-expressions.info/
Jan Goyvaertsi netisait. Ühinen Rex Egg autori kiidusõnadega!
5. http://www.princeton.edu/~mlovett/reference/Regular-Expressions.pdf
Jan Goyvaertsi Princetonis kirjutatud ülevaade regulaarsetest avaldistest.
....
Tõenäoliselt lisan korralikuma bibliograafia perli osas hiljem.
Näpuotsaga eestikeelseid viiteid:
1. http://kuutorvaja.eenet.ee/programmeerimine/regulaaravaldised.html
2. https://wiki.itcollege.ee/index.php/Regulaaravaldis
3. http://viki.keeleleek.ee/wiki/Regulaaravaldised
Probleemiks on terminoloogia. Pakkusin siinsetes lugudes mõnedele terminitele vasteid välja, nii teeb aga igaüks. Ühtse terminoloogia puudumine aga teeb väga raskeks omavahelise arusaamise.
Inglise keel alati ei aita, sest me ei suhte päevad läbi inglise keeles.
.... Isiklikult tunnen puudust Ustus Agurist. Eestikeelne It terminoloogia ajalugu jaguneb laias laastus kaheks ajastuks:
Aguri aegne (agurismid!), kuni 1997
ja post Aguri aegne anarhia, kus me praegu asume.



Regulaaravaldised ja grep I

I Lihtsalt GREP
















Hallo jälle!

Et mitte jääda üldsõnaliseks, võtaksin ette lubatud regulaaravaldiste uuringu ja kasutuse *nix töövahendi grep abil.
Selle lühendi päritolust huvitunu vaadaku minu eelnevat lugu 'Alguses oli ed'.
grep pärineb editori ed käsust g/re/p
ehk global, regular expression ja print.
Nii see asi üldjoontes toimibki, grep võtab sisendist
järjest ridu ja valib neist sobivad välja. Need väljastatakse ehk prinditakse.
Sobivus tehakse kindlaks regulaaravaldise põhjal.

Miks grep/ miks regulaaravaldised?

* Õnneks (fännide jaoks, kuhu ka mina kuulun) / kahjuks (mittefännide) jaoks on see arvutiasjanduse teoreetilise poole jaoks üsna oluline ja annab kursuse „Automaadid, keeled, translaatorid” läbimisel TÜ-s 6 arvestuspunkti.
Seal, tõsi, peab muid asju ka lisaks uurima.
See teooria algab aga üldjoontes sellest, et kirjutatud skriptiread analüüsitakse läbi regulaaravaldisi kasutava vahendi abiga.
Umbes sama, nagu Maxwelli võrrandid füüsikule, arvan mina füüsika vastava kadalipu läbinuna.
Võib-olla ei lähegi teil seda tööalasel reinkarneerumisel enam vaja, aga ei kujuta ette füüsikut, kes mõistet Maxwelli võrrand ei tea. Selles mõttes muidugi, et ta teab, et on teadnud.

*Õnneks (fännide jaoks) on Unix majandamine/sättimine põhinev tekstifailidel ja nendest kasulike terade väljasõelumisel on regulaarsed avaldised suureks abiks. Enamasti küll kõige lihtsamas vormis, kus „avaldise” asemel on lihtsalt otsitav sõne ja otsitakse tähttähelist ehk literaalset vastavust.

* Programmeerijate jaoks aga on iva vahest selles, et nende endi kokkukirjutatud koodilasu seast vajalikke juppe üles leida ja vajadusel ka modifitseerida. Tekstifailid on endiselt programmeerijate põhiline andmebaas ja selle andmebaasi haldamise üheks töövahendiks on regulaaravaldisi kasutavad vahendid. Saab ka ilma läbi, nagu foorumitestki selgub. Mõni armastab, mõni vihkab.
Nagu ikka selles maailmas.

* Aga TEGELIKULT on need minu jaoks on need päris huvitavad mõtteharjutused. Ning sellest piisab täiesti.
Tegelikult on see jutt nende asjade suurest kasust lihtsalt teadvale valele pikemate jalgade allakasvatamiseks. Jah, akadeemilisi punkte saab, aga saab ilma ka läbi. Jah, võib tööintervjuulgi kõvem tegija olla – aga sealgi võivad küsitlejate staatuses olla need, kellel on selline eelarvamus kusagil juba pähe istutatud, et regex on HEA ASI.
Sudokudega jahmerdamisel ma ei pea hakkama põhjendama, miks selline asi nii hiiglama hea on.

Jamie Zawinski: (üteluse väljastamise ajal Netscape insener)
Mõned inimesed mõtlevad mingit probleemi nähes -
„Tean, et hakkan kasutama regulaaravaldisi.”

Nüüd on neil kaks probleemi.


Kuidas see kõik algas?

1943 avaldasid Warren McCulloch ja Walter Pitts artikli
A logical calculus of the ideas immanent in nervous activity”.
ON võrdlemisi raske aru saada, et siin võiks üldse pistmist olla millegiga, millest saavad tulevikus regulaaravaldised. Tegemist on neuroteadusega ja neurovõrke kirjeldadakse, nagu hiljem selgus, lõplike automaatide keeles.
1955 aga arendas Stephen Kleene teooriat edasi.
Inimese moodi saab sellest lugeda hm. siiski lugeda wikist.

1968 ilmutas Ken Thompson artikli, kus kirjeldas (ja realiseeris) algoritmi, kus regulaaravaldiste põhjal saab kiiresti teada, kas vastavus on leitud, või mitte etteantud teksti sees. http://www.fing.edu.uy/inco/cursos/intropln/material/p419-thompson.pdf

Algoritm oli efektiivne ja siit see asi algas, sest seda oli suhteliselt lihtne realiseerida ning ka praktiline.
Ken Thompson realiseeris selle editoris ed – vt. 'Alguses oli ed' käsuna g/re/p.
Aga kõiki regulaaravaldisi grep ei realiseerinud. Ainult „põhilisi”.
Praegusel ajal kajastub see selles, et grep vaikimisi käivitub „baasrezhiimis”, kus kõiki asju ei ole sisse kirjutatud (grep – G).
Laiendatud grep, extended grep või egrep valmis Alfred Aho kirjutatuna 1979.
See on nüüd see grep, millega põhiliselt peaksime tegelema. Kõik Kleene poolt sissekirjutatud võimalused on egrep-s olemas.
Käivitage linux-is grep -E – see on sama, mis egrep.

Kuid ilma PERL programmeerimiskeeleta ei oleks regulaaravaldised iialgi muutunud kultuseks. Perlis on regulaarne avaldis kultusobjekt ja
Larry Wall lisas siia mitmeid vahepeal leiutatud võimalusi, mis enam Kleene poolt kirjeldatud süsteemi ei kuulu. Nii ongi „laiendatud” regulaaravaldiste järel perl mõjutusel tekkinud veel rohkem laiendatud regulaarsed avaldised.
Tähejoru PCRE tähistab näiteks Perl Compatible Regular Expression-i, Perl-iga ühilduvat, mitte enam nii regulaarset avaldist.
.... Olgu. Aitab.
Ajaloo eest olge tänulikud põhiliselt järgmisele saidile:
http://blog.staffannoteberg.com/2013/01/30/regular-expressions-a-brief-history/
(ja muidugi wikile, keda ei viitsigi alati tänama hakata).

Hakkame greppima

Hakatuseks unustame regulaarsed avaldised peaaegu üldse ära.
Kui etteantud sõne sisaldub selles reas, siis on vastavus leitud. Lihtne literaalne ehk tähtäheline otsing niisiis:
'Arno' klapib reaga 'Kui Arno isaga ...'

Lihtsaks proovimiseks sobikski lõiguke „Kevadest” ja sealt greppimise näiteid.
Üheks võimalikuks nuhtluseks võib olla täpitähtede kodeering siin.
Ma olen üritanud püsida utf-8- piires. Aga mine sa seda õ-d tea!
Toon selle siin ära, kopeerige, peistige see klassika oma *nix-isse ja katsetage ja tippige kahtlased täpilised ümber, kui ei tule midagi nende täppidega grepis välja.
Või kirjutage midagi, mis paremini peale läheb ja greppige siis ära.
Tehke omale Linuxis kataloog grepp.
Sinna fail 'kevade' järgmise krestomaatilise sisuga:



Kui Arno isaga koolimajja jõudis, olid tunnid juba alanud.
Kooliõpetaja kutsus mõlemad oma tuppa,
kõneles nendega natuke aega, käskis Arnol olla hoolas ja ja seadis ta siis pinki ühe pikkade
juustega poisi kõrvale istuma.
Siis andis kooliõpetaja talle raamatust midagi kirjutada, ja Arnol ei olnud
nüüd enam aega muule mõtelda.
Ta võttis tahvli ja hakkas kirjutama.
Kui ta oli kirjutanud umbes paar rida, kummardus pikkade juustega poiss tema kõrva juurde ja küsis sosinal:
"Mis koolmeister ütles, kui te tema toas olite?"



Ja saabki hakata greppi uurima.
Kaua aretatud töövahendina on tal mitmeid käivitamise võimalusi, katsun need enam-vähem kirja panna (mitte manuaali täpsusega).

Grepi kasutuse 2 viisi

I

grep -VÕTMED REGULAARAVALDISED-MUSTRID FAILID/VÕI FAILIMUSTRID

II

xxx xxxx xxxx ... | grep -VÕTMED MUSTRID | ...

käskude vahel on siis konveieri / toru sümbol '|'

Kolmas viis on ka, seda ei tasu grafomaania all mittekannatavatel kasutada (või siiski, ainult et
grepitavaks võiks olla mõne teise kasutaja terminal?)

III

grep -VALIKUVÕTMED MUSTRID

Nüüd saate oma kirjanduslikke võimeid proovile panan. Teie loomingulise palangu lõpetab
sellel puhul Ctrl C.
Äraseletatult grep kuulab standardset sisendit, milleks on terminal ja selle taga istuv alustav linuxifänn... ja kui saadetakse signaal kuulamine lõpetada (Ctrl C), siis grep seda ka teeb.
Kui aga ei saadeta?

Detailsem selgitus

Alustame valikuvõtmetest. Nagu ikka Linux puhul võivad võtmed olla pikalt välja kirjutatud, või lühidalt.
Lühidalt tähendab ühe tähena.
Suured ja väiksed tähed on VÄGA erinevad valikud grep puhul. Võtmeid saab kirjutada kokku, näiteks kaks võtit -Ec koos, aga ka lahku, näiteks -E -c ...
Iga võtme jaoks on manuaalis toodud (man grep ) alati ka pikk variant. Näiteks ülaltoodud -E pikaks variandiks on –extended-regexp. Mõne pika variandi puhul lühikest ei ole --color ntx.
{
Siis näitab grep värvilist tulemit kohtades, kus oli klapp (match), kui pikalt kirjutada --color=auto,
siis näitab ekraani peal värvi, muude suunamiste puhul võtab grep värvid välja.
}

Kui te kirjutate mingit kesta skripti, võib pikkadel võtmetel olla mõte, käsurealt käivitusel tõenäoliselt mitte.
Mustrid (tavaliselt üks muster ) kohal peaks olema mingi hulk regulaaravaldisi. Kui neid rohkem tahetakse sisestada, siis iga mustri ees peaks olema uuesti kirjutatud võti -e.
Näiteks:

grep -e 'Kui' -e 'poiss' kevade

Mustreid võib koguni võtta failist, iga uus muster eraldi realt -f võti ütleb siis, et MUSTRID kohale võiks kirjutada failinime, kust neid mustreid võetakse.

Failide kohal võib olla üks või mitu faili.
Võib olla ka üldine muster.
*.c tähistab kõiki faile, mille lõpus on laiend .c
Aga failide mustrid ei ole regulaaravaldised.
Neist natuke ka edaspidi, aga võtmesõned globbing, bash expansion googlist aitavad selgitada seda, kuidas failinimed grep käsureale maabuvad.

Regulaaravaldiste mustrid tuleb kaitsta ühekordsete jutumärkidega. Sel juhul annab kestaprogramm bash selle mustri sisu programmile grep ilma modifitseerimata edasi.
Failimustreid jälle ärge kaitske mitte mingisuguste jutumärkidega - te ei saa kõiki .c laiendiga faile '*.c' kasutades.
Erandiks oleks vajadus kasutada keskkonnamuutujaid – siis kirjutage kahekordsed jutumärgid ja nende sisse siis see / need keskkonnamuutujad.
Päris ilma jutumärkideta võib ka proovida, aga varem või hiljem viib see ootamatute tulemiteni, asjad ei tööta nii, nagu tahetakse.

Grep kasutusvallad ilma regulaaravaldiste regulaarteadmisteta:

Erigreppide uputus:

80% juhtudel teame täpselt sõnet, mida otsime. See tulebki ühekordsete jutumärkide vahele kirjutada.
Aga oh häda! Mõnikord sisaldab otsitav sõne regulaaravaldiste jaoks eri ehk metasümboleid.

Kuna selliseid erijuhte on nii palju, siis on selle jaoks vanal ajal leiutatud eraldi grep nimega
fgrep. fgrep jaoks ei ole mustrid mingid regulaaravaldised, vaid tavalised sõned / stringid.
Samamoodi grepi täiustuseks on leiutatud egrep, mis jälle neid regulaaravaldisi rohkem tunneb ning lõpuks rgrep,
mis oskab käia mööda alamakatalooge.
Ühel ilusal päeval arvati siiski, et neid greppe saab isegi Linuxi jaoks natukene liiga palju (väikesed tööriistad, mis teevad praktiliselt väga sarnast asja ja mis Unixi filosoofiale erandlikult lõpuks jälle kokku liideti).
Tänasel päeval öeldakse egrep, fgrep, rgrep kasutuste kohta 'deprecated' (moest läinud) ja kasutatakse selle asemel
grep -E
grep -F
(jah, -F, mitte -f, mis tähendab failist lugemist).
grep -r
(ja väga üllatuslikult ka grep -R tähistab sama, ülejäänud juhtudel on väike ja suuretähelised võtmed VÄGA erinevad).
Mida -r/R, -E võtmed teevad, sellest allpool.
grep -F MUSTRID / või grep -Ff MUSTRIFAIL lihtsalt võtab sõnesid tähttähelt ja otsib ridades nende vastavusi.
Olgu näiteks meil teada, et firma arendusosakonnas töötavad Toomas, Paul, Juhan ja Kalle.
Mustrifailis on read Toomas Lepp, Paul Kask, Juhan Kuusk ja Kalle Mänd.
Ühe käsuga saame välja greppida kõik read otsitavates failides, kus neist kodanikest nende pika nimega juttu on.

Mida aga tulemustega teha?

Lihtsalt read kusagil failis / ekraanil ei pruugi anda palju infot. Et lisada faili nimi, kust mustriga klappiv rida pärit, on olemas võti -H.

grep -H 'Arno' kevade

kevade:Kui Arno isaga koolimajja jõudis, olid tunnid juba alanud.
kevade:kõneles nendega natuke aega, käskis Arnol olla hoolas ja ja seadis ta siis pinki ühe pikkade
kevade:Siis andis kooliõpetaja talle raamatust midagi kirjutada, ja Arnol ei olnud

Kui faile on 1, ei lisata niikuinii failinimesid, aga kui neid on rohkem, lisatakse failinimi vaikimisi ja neist saab lahti ainult -h võtit teades.

cp kevade kevade1
grep 'Arno' *
grep -h 'Arno' *


Et lisada rea numbrit, on olemas võti -n.
Tõsi, lihtsam on lihtsalt rea numbri lisamiseks cat -n kasutamine.

grep -n '' kevade >kevade1
cat kevade1

(Tühi muster '' klapib iga reaga (aga tühi fail, kus polegi mustreid, ei klapi millegagi).

Seda võtit tasub kasutada failile reanumbrite juurdelisamisel!
Ja siis ka, kui mõnes programmijupis on vaja teada, mis real mingi 'jama' paikneb.

Et väljastada AINULT faili nimi, kust rida pärit, on võti -l, aga -L väljastab sellise faili nime, kus
klappi MUSTRITEGA ei leitud.

grep -l 'Arno' *

kevade
kevade1

grep -L 'Arno' *

grep -L '5' *
kevade

Äkki tunneme huvi vaid sõna / nime 'Arno' vastu (siin küll pigem vastupidi, ka Arno eesti keele käänetes on vajalik ära tunda)?
Väike, KINDLASTI väike w aitab siis.

grep -w 'Arno' kevade

Suur võti -W on grepile tundmatu ja greppija saab korvi:

Mõnikord tahame teada, palju ridu meie mustritega klapib.
-c loeb need READ üle. Mitte klappide arv, see võib suurem olla!

grep -wc 'Arno' *

kevade:3
kevade1:3

Huvitav, kuidas siit võiks saada ridade koguarvu?
Appi tuleb võtta 'Alguses oli ed' st tuttav awk.

grep -ch 'Arno' * | awk '{ sum += $1 } END { print sum }'

6

Väikese vaevaga saab siit nüüd rea, mis mingi programmeerimse projekti puhul loeb ära,
mitu rida arendajad tööd on teinud.

grep -rch --include='*.c' --include='*.h' '' . | awk '{ sum += $1 } END { print sum }'

mõõdab ära C projekti seas olevate koodiridade arvu, kui olete selle projekti ruudukataloogis.

Selgitusi: -r - programm käib mööda antud kataloogi '.' ja tema alamkatalooge mööda.

Iga kord, kui grepi failide reas kohtame mingit kataloogi, ütleb võti -r, et mine selle kataloogifaili sisse ja hakka seal samamoodi faile läbi vaatama. Kui include-t ei ole, vaadatakse läbi kõik failid.
Kui '.' asemele oleksime pannud * sümboli, siis kõigepealt oleks bash
asendanud '*' selles kataloogis olevate kõikide failide loendiga (nii see Unix tehtud on, bash teeb enne sellised asendused ära) ja siis oleks grep need failid üle vaadanud. Kataloogifailides oleks välja valitud *.c ja *.h failid, aga jooksvas kataloogis vaadatakse üle KÕIK failid, mis sellest, et
--include keelaks nagu selle ära.

Mõnikord huvitab meid see, et grep teeks tööd ainult tekstifailidega (enamasti nii ongi). Selleks PEATE eraldi võtme panema, -I.
Nüüd mistahes failide korral, kus Unix arvab, et need on binaarsed, grep lõpetab tegevuse (0 vastavust).
Aga kui UNIX on veendumusel, et tegemist ikkagi on tekstifailiga, loetakse seal oleva binaarsest jurast sõltumatult see greppi sisse ja teatatakse absurdsetest tulemitest, näiteks ridade arvust binaarfailis.
Nii et -r võtme korral on vaja otseselt ära märkida KATALOOGID, kust grep hakkab faile otsima ning alati ka --include=MUSTER abiga sobivad laiendid, ilma selleta võite saada ootamatuid tulemusi.

EITUS

Eituseks kasutage võtit -v.

grep -v 'Arno' kevade

kevade:Kooliõpetaja kutsus mõlemad oma tuppa,
kevade:juustega poisi kõrvale istuma.
kevade:nüüd enam aega muule mõtelda.
kevade:Ta võttis tahvli ja hakkas kirjutama.
kevade:Kui ta oli kirjutanud umbes paar rida, kummardus pikkade juustega poiss tema kõrva juurde ja küsis sosinal:
kevade:"Mis koolmeister ütles, kui te tema toas olite?"
kevade:

Klappimiste arvust veel kord

Teame nüüd, et
grep -c 'Arno' kevade
mõõdab ära, mitmel REAL esines nimi Arno. Vastus on, et Kevade esimeses lõigus mainiti teada 3 korda.
Aga mis siis saab, kui Arnot on samal real MITU korda?

Selle ülelugemiseks saab kasutada -o võtit.
-o kirjutab eraldi reale välja täpse klappimuse, täpse vastavuse ja mitte midagi muud.
See paistab üsna totter olevat, sest kui nüüd teha

grep -o 'Arno' kevade,

saame 3 -le reale sellesama Arno.
Arno
Arno
Arno

See võiks omada mingit mõtet siis, kui me tõesti otsime mingite kavalate regulaaravaldiste abil erinevaid vastavusi tekstis?

Kuid isegi sellise tähttähelise klapi korral on sellel totrusel kasulikke omadusi!
Oletame näiteks, et tahame teada, mitu korda 'Kevades' on kasutatud tähte 'k'.
Piirdume esialgu selle esimese lõiguga:

grep -oi 'k' kevade | wc -l

annab selle vastuse - meie tekstis oli 26 k-d.
Võti -i teeb otsingu 'tõstutundetuks'.

Miks mitte kasutada tähtede lugemist selleks, et vaadata, kui keskmiselt hästi Oskar Luts kirjutas? Kui kõikide häälikute keskmine sagedus on paigas, siis on tegemist täieliselt keskmise Eesti tekstiga ja me võime rahvakirjanikuga rahule jääda.

Harjutamiseks kasutame ka ühte lihtsaimat regulaaravaldist:
'[a-z]' - nurksulgudes on toodud loetelu lubatud tähtedest, sidekriips tähistab vahemikku, praegu siis kõiki tähti. Kui teil on õieti paigas kasutatav kooditabel, on kõik hästi ja sinna sisse mahuvad ka täpitähed. Võib juhtuda, et kavalam oleks kirjutada otse välja täpilised juhtumid. a-z sisaldab kindlasti ladina tähti, aga eraldi välja kirjutada tuleks ?kõik (ka väiksed ja suured täpitähed).
Seega selline regulaaravaldis: '[a-zõäöüÕÄÖÜ]'.
Kolmas võimalus alfabeetiliste tähtede nimetamiseks oleks spetsiaalne nimi:
'[:alpha:]'

Nüüd käsk

grep -oi '[a-z]' kevade | sort | uniq -c | sort -nr
VÕI
grep -oi '[a-zõäöüÕÄÖÜ]' kevade | sort | uniq -c | sort -nr
VÕI
grep -oi '[[:alpha:]]' kevade | sort | uniq -c | sort -nr

loeb ära ja järjestab erinevad tähed (suurtähtede väljaloopimine jäägu mõneks teiseks korraks!) selles lõigus.
Saame teada, et Lutsul oli tähtede sagedusjärjestus Kevade esimeses lõigus selline:
62 a
40 i
33 s
31 e
29 u
28 t
24 l
23 o
23 k
19 d
17 n
17 m
17 j
14 r
10 p
9 õ
7 g
5 ü
4 v
4 h
3 K
3 A
2 b
1 T
1 S
1 M
1 ä
'aiseutlokdnmj...' võiks olla eesti keele tähtede umbkaudne sagedusjärjestus, seda ÜHEL UNIXI käsureal saavutatuna.
Kui annaksite mulle ette terve 'Kevade', hindaks juba täpsemini tähtede sageduse ära.
Ja nii saab mõõta ka sõnu, näiteks võiks see meetod kiiresti anda vastuse küsimusele, kes kirjutas
'Talve', seda kõike ainult UNIX kesta vahenditega. Edaspidi ka sellest ja kust see rida, mis tähtede sagedusi mõõtis, on võetud...

Nii et see kärbseid ja täisid täis 'Ida Aafrika' maakoht tasapisi muutub päris põnevaks programeerimise laboratooriumiks!
Kontroll: Nagu võib teada saada saidilt
on eesti keele tähtede sagedus selline:
A, E, I, S, T , L, U, N, K, M , O, D, R, V, G , H, J, P, Ä, Õ , B, Ü, Ö, F, Š , Ž, C, W, Y, Z , X, Q.

Nagu näete, saime PÄRIS HEA KLAPI, seda vaid ühe Unix käsurea abiga!!
Luts on täiesti keskmine Eesti kirjanik, ei rohkem ega vähem.
Ja Arno isaga veel väga, väga kaua aega jõuavad kooli alles siis, kui tunnid on juba alanud (ja regulaarsed avaldised läbi võetud).