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.txtotsib mustritgrep -nnäitab reanumbreidgrep -ieirab tõstutundlikkustgrep -rotsib rekursiivseltgrep -vpöörab vaste ümber
Kõige sagedasemad valikud alguses:
-nreanumbrid-itõstutundetu otsing-rrekursiivne otsing-vnäita mittevastavaid ridu-Elaiendatud regulaaravaldis-Fotsi 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:
grepotsib tavalise mustri järgiegreptähistas laiendatud regulaaravaldisifgreptä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
grepvõigrep -E
Kiired töökujud
grep 'muster' fail.txtotsib ühest failist sobivad readgrep -n 'muster' fail.txtlisab väljundisse reanumbridgrep -i 'muster' fail.txteirab tõstutundlikkustgrep -r 'muster' .otsib rekursiivselt praegusest kaustastgrep -F 'sõne' fail.txtotsib täpset sõnet ilma regexitagrep -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:
- too andmed alla
- tee need ühtlaseks
- 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ähtedeksgrep -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:
-xtä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:
curlvõiwget- torud
trgrep -Egrep -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.lleidis mitu 5-tähelist sõna grep -o .lõhkus iga vaste üksikuteks märkidekssort | uniq -c | sort -nrnäitas, milliseid tähti nendes vastetes esineb kõige rohkem
See näide on hea ka sellepärast, et ta ühendab mitu peatükki:
grepotsib mustri järgitrmuudab teksti kujusortjauniq -ckoondavad 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\1tä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:
aaaaaasobib, sestaakordub kolm kordaa.a.a.sobib, sesta.kordub kolm kordaratatatsobib, sest reas leidub alammusteratatat, kusatkordub kolm korda
See viimane on eriti õpetlik, sest siin tuleb välja veel üks oluline asi:
- ilma
-x-ta otsibgrepvastet 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
- Loo fail, kus on viis sõna eri ridadel.
- Otsi üht sõna tõstutundlikult ja siis tõstutundetult.
- Otsi rekursiivselt sõna
TODOmõnes projektikaustas. - Võta suuremast sõnaloendist ainult väiketähelised alfanumbrilised read ja otsi neist mustriga
grep -x. - Proovi GNU
grep-iga mustrit( .. )\1\1+ilma tühikuteta ja selgita, miksratatatsobib ilma-x-ta.