Mustand: sisu ei ole veel tehniliselt ega keeleliselt täielikult kontrollitud ega toimetatud.

Peatüki vaade

Linux/Unix/macOS käsurea kiirõpik

Praegu loed peatükki Teksti otsimine: grep ja sugulased, mis kuulub osasse Osa IV: Tekst, otsing ja automatiseerimine.

Teksti otsimine: grep ja sugulased

Selles peatükis õpime otsima teksti tööriistadega grep, egrep, fgrep ja moodsamate vastetega.

Loogika

grep on seotud torude, failide ja logidega, sest ta võtab ridu sisse ja valib neist välja need, mis sobivad mustriga.

See tähendab, et grep-i kasutatakse väga tihti koos:

  • failidega
  • torudega
  • logide ja konfiguratsioonidega

Kõige olulisem mõte on: grep ei “tee teksti targemaks”, vaid filtreerib ridu.

Kiirspikker

  • grep 'muster' fail.txt otsib mustrit
  • grep -n näitab reanumbreid
  • grep -i eirab tõstutundlikkust
  • grep -r otsib rekursiivselt
  • grep -v pöörab vaste ümber

Kõige sagedasemad valikud alguses:

  • -n reanumbrid
  • -i tõstutundetu otsing
  • -r rekursiivne otsing
  • -v näita mittevastavaid ridu
  • -E laiendatud regulaaravaldis
  • -F otsi fikseeritud sõnet, mitte regexit

Käivita need käsud


printf 'kass\nkoer\nKass\n' > loomad.txt
grep 'kass' loomad.txt
grep -i 'kass' loomad.txt
grep -n 'koer' loomad.txt

grep -r 'TODO' .
grep -v '^#' seadistus.conf

grep, egrep, fgrep

Ajalooliselt:

  • grep otsib tavalise mustri järgi
  • egrep tähistas laiendatud regulaaravaldisi
  • fgrep tähistas fikseeritud teksti

Tänapäeval kasutatakse sageli:


grep -E 'muster'
grep -F 'sone'

Praktiline reegel:

  • kui otsid lihtsalt täpset teksti, siis grep -F
  • kui otsid mustrit, siis grep või grep -E

Kiired töökujud

  • grep 'muster' fail.txt otsib ühest failist sobivad read
  • grep -n 'muster' fail.txt lisab väljundisse reanumbrid
  • grep -i 'muster' fail.txt eirab tõstutundlikkust
  • grep -r 'muster' . otsib rekursiivselt praegusest kaustast
  • grep -F 'sõne' fail.txt otsib täpset sõnet ilma regexita
  • grep -R 'muster' . otsib rekursiivselt ka siis, kui all on alamkaustad

Väga praktiline 1-liner on:


grep -R 'TODO' .

See on sageli üks kiiremaid viise aru saada:

  • kus projektis mingi sõna või märksõna esineb
  • kas mõni seadistus, URL või funktsiooninimi on üldse olemas

Päris näide: suur sõnaloend ja mustriotsing

Siin on hea näha, kuidas grep on seotud ka teksti puhastamise ja torudega. Mõte ei ole lihtsalt "otsi faili seest", vaid:

  1. too andmed alla
  2. tee need ühtlaseks
  3. otsi huvitavat mustrit

Kui sul on veebis oma andmekaust, on mugav kasutada baas-URL-i:


BASE_URL="https://sinu-domeen/~vilo/linux"
curl -L "$BASE_URL/data/words.txt" -o words.txt

Kui tahad teha samu katseid ilma veebita, sobib hästi ka repo lokaalne fail:


cp data/generated-words.txt words.txt

Kui fail on juba kohalikus kaustas olemas, võid alustada otse sellest.

Järgmine samm on teha sõnad väikesteks tähtedeks ja jätta alles ainult read, mis koosnevad tähtedest või numbritest:


tr '[:upper:]' '[:lower:]' < words.txt | grep -E '^[[:alnum:]]+$' > words-clean.txt

Siin:

  • tr '[:upper:]' '[:lower:]' teeb sõnad väikesteks tähtedeks
  • grep -E '^[[:alnum:]]+$' jätab alles ainult need read, kus terve rida koosneb tähtedest või numbritest
  • tulemus kirjutatakse faili words-clean.txt

Nüüd saab teha huvitavama otsingu:


grep -x '..a..t..l.' words-clean.txt

Oluline loogika:

  • -x tähendab, et muster peab katma kogu rea
  • . tähendab "üks suvaline märk"
  • muster ..a..t..l. otsib 10-märgilisi ridu, kus:
  • kolmas märk on a
  • kuues märk on t
  • üheksas märk on l

Kui vasteid on liiga palju, lisa näiteks:


grep -x '..a..t..l.' words-clean.txt | head

Või loenda vasteid:


grep -x '..a..t..l.' words-clean.txt | wc -l

See on hea näide, sest siin saavad kokku:

  • curl või wget
  • torud
  • tr
  • grep -E
  • grep -x

See on juba päris töövoog, mitte ainult üksik käsunäide.

Päris terminali transkript

Allpool on tahtlikult veidi "päris elu moodi" terminali näide, mitte täiesti steriilne retsept. See on kasulik, sest näitab ka olukorda, kus esimene otsing ei anna midagi ja alles järgmine samm teeb tulemuse nähtavaks.


vilo@Mac tmp % wget https://raw.githubusercontent.com/dwyl/english-words/refs/heads/master/words.txt
...
'words.txt' saved

vilo@Mac tmp % cat words.txt | grep -x 'a..y..l.e'

vilo@Mac tmp % cat words.txt | tr 'A-Z' 'a-z' | grep -x 'a..y..l.e'
abbyville

vilo@Mac tmp % cat words.txt | tr 'A-Z' 'a-z' | grep -x 'a.t.l'
antal
aptal
artal
artel
astel
attal
axtel

vilo@Mac tmp % cat words.txt | tr 'A-Z' 'a-z' | grep -x 'a.t.l' | grep -o .
a
n
t
a
l
a
p
t
a
l
a
r
t
a
l
a
r
t
e
l
a
s
t
e
l
a
t
t
a
l
a
x
t
e
l

vilo@Mac tmp % cat words.txt | tr 'A-Z' 'a-z' | grep -x 'a.t.l' | grep -o . | sort | uniq -c | sort -nr
  11 a
   8 t
   7 l
   3 e
   2 r
   1 x
   1 s
   1 p
   1 n

Selle töövoo loogika on:

  • esimene grep -x 'a..y..l.e' ei leidnud midagi, sest failis oli vaste suure algustähega
  • tr 'A-Z' 'a-z' muutis sisendi väiketäheliseks
  • pärast seda leidus vaste abbyville
  • muster a.t.l leidis mitu 5-tähelist sõna
  • grep -o . lõhkus iga vaste üksikuteks märkideks
  • sort | uniq -c | sort -nr näitas, milliseid tähti nendes vastetes esineb kõige rohkem

See näide on hea ka sellepärast, et ta ühendab mitu peatükki:

  • grep otsib mustri järgi
  • tr muudab teksti kuju
  • sort ja uniq -c koondavad tulemuse statistikaks

Praktiline märkus: kui tahad õpetada lihtsalt mustriotsingut, siis võib toru cat words.txt | ... asemel kirjutada lühemalt:


tr 'A-Z' 'a-z' < words.txt | grep -x 'a..y..l.e'

Aga transkriptis on pikem kuju täiesti sobiv, sest ta näitab torude loogikat väga nähtavalt.

Fun fact: tagasiviited ja korduv muster

GNU grep toetab ka tagasiviiteid. See tähendab, et saad öelda: "otsi midagi, kus seesama eelnevalt leitud tükk kordub uuesti".

Näide:


vilo@Mac tmp % cat words.txt | tr 'A-Z' 'a-z' | grep -E '(..)\1\1+'
a.a.a.
aaaaaa
k.k.k.
larararia
logogogue
ratatat
ratatats
ratatat-tat

Selle mustri loogika on:

  • (..) võtab kaks suvalist märki ja jätab need meelde
  • \1 tähendab "sama kahe märgi paar uuesti"
  • teine \1+ tähendab, et see sama paar kordub veel vähemalt ühe korra

Seega otsitakse ridadest kohta, kus mingi kahe märgi paar kordub vähemalt kolm korda järjestikku.

Näited:

  • aaaaaa sobib, sest aa kordub kolm korda
  • a.a.a. sobib, sest a. kordub kolm korda
  • ratatat sobib, sest reas leidub alammuster atatat, kus at kordub kolm korda

See viimane on eriti õpetlik, sest siin tuleb välja veel üks oluline asi:

  • ilma -x-ta otsib grep vastet rea seest
  • -x-ga peab kogu rida mustriga sobima

See tähendab, et:


cat words.txt | tr 'A-Z' 'a-z' | grep -E '(..)\1\1+'

otsib rea seest sobivaid kohti, aga:


cat words.txt | tr 'A-Z' 'a-z' | grep -x -E '(..)\1\1+'

nõuab, et terve rida koosneks sellisest korduvast mustrist.

Praktiline märkus: see on hea "regexi mängumaa" näide, aga täiesti igapäevaseks tekstifiltreerimiseks ei ole tagasiviited alati parim tööriist. GNU grep dokumentatsioon hoiatab, et tagasiviited võivad olla aeglasemad ja mõnikord probleemsemad kui lihtsamad mustrid.

Minitest

  1. Loo fail, kus on viis sõna eri ridadel.
  2. Otsi üht sõna tõstutundlikult ja siis tõstutundetult.
  3. Otsi rekursiivselt sõna TODO mõnes projektikaustas.
  4. Võta suuremast sõnaloendist ainult väiketähelised alfanumbrilised read ja otsi neist mustriga grep -x.
  5. Proovi GNU grep-iga mustrit ( .. )\1\1+ ilma tühikuteta ja selgita, miks ratatat sobib ilma -x-ta.