Program educațional despre GREP și expresii regulate. Expresii regulate și comanda grep Exemple linux de expresii regulate

Bună ziua, invitați!

În articolul de astăzi vreau să ating un subiect atât de mare ca Expresii regulate. Cred că toată lumea știe că subiectul regexe (cum sunt numite expresiile regulate în argou) este vast în domeniul de aplicare a unei postări. Prin urmare, voi încerca să îmi adun pe scurt, dar cât mai clar posibil, gândurile și să vi le transmit în .

Permiteți-mi să încep prin a spune că există mai multe tipuri de expresii regulate:

1. Expresii regulate tradiționale(sunt, de asemenea, de bază, de bază și expresii regulate de bază(BRE))

  • Sintaxa acestor expresii este definită ca fiind învechită, dar totuși este încă răspândită și utilizată de multe utilitare UNIX
  • Expresiile regulate de bază includ următoarele metacaractere (mai multe despre semnificațiile lor mai jos):
    • \( \) - versiunea inițială pentru ( ) (în extins)
    • \(\) - versiunea inițială pentru () (în extins)
    • \n, Unde n- număr de la 1 la 9
  • Caracteristici ale utilizării acestor metacaractere:
    • Un asterisc trebuie să urmeze expresia corespunzătoare unui singur caracter. Exemplu: *.
    • Expresia \( bloc\)* ar trebui considerat incorect. În unele cazuri, se potrivește cu zero sau mai multe repetări ale șirului bloc. În altele corespunde șirului bloc* .
    • În cadrul unei clase de caractere, semnificațiile caracterelor speciale sunt în mare măsură ignorate. Cazuri speciale:
    • Pentru a adăuga un caracter ^ la un set, acesta nu trebuie să fie plasat primul acolo.
    • Pentru a adăuga un caracter - la un set, acesta trebuie plasat acolo primul sau ultimul. De exemplu:
      • Șablon de nume DNS, care poate include litere, cifre, minus și un punct: [-0-9a-zA-Z.] ;
      • orice caracter, cu excepția minusului și a numerelor: [^-0-9] .
    • Pentru a adăuga un caracter [ sau ] la un set, acesta trebuie plasat mai întâi acolo. De exemplu:
      • potrivește ], [, a sau b.

2. Expresii regulate avansate(si sunt expresii regulate extinse(ERE))

  • Sintaxa acestor expresii este similară cu sintaxa expresiilor principale, cu excepția:
    • S-a eliminat utilizarea barelor oblice inverse pentru metacaracterele ( ) și ().
    • O bară oblică inversă înaintea unui metacaracter depășește semnificația sa specială.
    • Respins teoretic neregulat proiecta\ n .
    • S-au adăugat metacaractere + , ? , | .

3. Expresii regulate compatibile cu Perl(si sunt Expresii regulate compatibile cu Perl(PCRE))

  • au o sintaxă mai bogată și în același timp previzibilă decât chiar și POSIX ERE, deci sunt adesea folosite de aplicații.

Expresii regulate constau dinșabloane, sau mai degrabă setați un șablon căutare. Șablonul constă din reguli căutări, care sunt alcătuite din personajeŞi metacaracterele.

Reguli de căutare sunt determinate de următoarele operațiuni:

Enumerare |

țeavă (|) separă opțiunile valide, s-ar putea spune - SAU logic. De exemplu, „gri|gri” se potrivește gri sau gri.

Grup sau sindicat()

Paranteze sunt folosite pentru a defini domeniul și prioritatea operatorilor. De exemplu, „gri|gri” și „gr(a|e)y” sunt modele diferite, dar ambele descriu un set care conține griŞi gri.

Cuantificare()? * +

Cuantificator după ce un personaj sau un grup determină de câte ori antecedente poate apărea expresia.

expresie generală, repetările pot fi de la m la n inclusiv.

expresie generală m sau mai multe repetări.

expresie generală nu mai mult de n repetări.

netezin repetări.

Semnul întrebării mijloace 0 sau 1 ori, la fel ca {0,1} . De exemplu, „culoare” se potrivește și culoare, Și culoare.

Stea mijloace 0, 1 sau orice număr odata ( {0,} ). De exemplu, „go*gle” se potrivește ggle, Google, google etc.

Plus mijloace cel putin 1 odata ( {1,} ). De exemplu, „go+gle” se potrivește Google, google etc. (dar nu ggle).

Sintaxa exactă a acestor expresii regulate este dependentă de implementare. (adică în de bază expresii regulate X simboluri (Și)- a scăpat cu o bară oblică inversă)

Metacaracterele zicală într-un limbaj simplu- acestea sunt simboluri care nu corespund semnificației lor reale, adică un simbol. (punct) nu este un punct, ci orice caracter etc. Vă rugăm să vă familiarizați cu metacaracterele și semnificațiile lor:

. corespunde singur orice simbol
[ceva] Conform orice singur caracter dintre cele cuprinse între paranteze. În acest caz: Caracterul „-” este interpretat literal doar dacă este situat imediat după o deschidere sau înainte de o paranteză de închidere: sau [-abc]. În caz contrar, denotă un interval de caractere. De exemplu, se potrivește cu „a”, „b” sau „c”. corespunde literelor mici ale alfabetului latin. Aceste denumiri pot fi combinate: potrivește a, b, c, q, r, s, t, u, v, w, x, y, z Pentru a potrivi caracterele „[” sau „]”, este suficient ca paranteza de închidere a fost primul caracter după caracterul de deschidere: se potrivește cu „]”, „[”, „a” sau „b” Dacă valoarea dintre paranteze drepte este precedată de un caracter ^, atunci valoarea expresiei se potrivește un singur personaj dintre aceia. De exemplu, [^abc] se potrivește cu orice alt caracter decât „a”, „b” sau „c”. [^a-z] se potrivește cu orice caracter, cu excepția caracterelor minuscule din alfabetul latin.
^ Se potrivește cu începutul textului (sau începutul oricărei linii dacă modul este linie cu linie).
$ Se potrivește cu sfârșitul textului (sau sfârșitul oricărei rânduri dacă modul este linie cu linie).
\(\) sau () Declara o „subexpresie marcată” (expresie grupată) care poate fi folosită ulterior (vezi elementul următor: \n). O „subexpresie marcată” este, de asemenea, un „bloc”. Spre deosebire de alți operatori, acesta (în sintaxa tradițională) necesită o bară oblică inversă în extins și Perl, caracterul \ nu este necesar;
\n Unde n- acesta este un număr de la 1 la 9; corespunde n a-a subexpresie marcată (de exemplu (abcd)\0, adică caracterele abcd sunt marcate cu zero). Acest design este teoretic neregulat, nu a fost acceptat în sintaxa extinsă a expresiei regulate.
*
  • Stea după o expresie care se potrivește cu un singur caracter, se potrivește zero sau Mai mult copii această expresie (precedentă). De exemplu, „*” se potrivește cu șirul gol, „x”, „y”, „zx”, „zyx”, etc.
  • \n*, Unde n este o cifră de la 1 la 9, se potrivește cu zero sau mai multe apariții n subexpresia marcată. De exemplu, „\(a.\)c\1*” se potrivește cu „abcab” și „abcaba”, dar nu cu „abcac”.

O expresie inclusă în „\(” și „\)” urmată de un „*” ar trebui considerată ilegală. În unele cazuri, se potrivește cu zero sau mai multe apariții ale șirului care a fost inclus în paranteze. În altele, se potrivește cu expresia cuprinsă între paranteze, având în vedere caracterul „*”.

\{x,y\} Corespunde ultimului ( viitoare) bloc care apare cel puțin x si nu mai mult y dată. De exemplu, „a\(3,5\)” se potrivește cu „aaa”, „aaaa” sau „aaaaa”. Spre deosebire de alți operatori, acesta (în sintaxa tradițională) necesită o bară oblică inversă.
.* Desemnarea oricărui număr de caractere între două părți ale unei expresii regulate.

Metacaracterele ne ajută să folosim diferite potriviri. Dar cum putem reprezenta un metacaracter ca un caracter obișnuit, adică simbolul [ (paranteză pătrată) cu sensul unei paranteze pătrate? Doar:

  • trebuie precedat ( scut) metacaracter (. * + \ ? ( )) bară oblică inversă. De exemplu \. sau \[

Pentru a simplifica definirea unor seturi de caractere, acestea au fost combinate în așa-numitele. clase si categorii de personaje. POSIX a standardizat declararea anumitor clase și categorii de caractere, așa cum se arată în următorul tabel:

Clasa POSIX în mod similar desemnare
[:superior:] caractere majuscule
[:jos:] caractere mici
[:alfa:] caractere mari și mici
[:alnum:] numere, litere mari și mici
[:cifră:] numere
[:xdigit:] cifre hexazecimale
[:punct:] [.,!?:…] semnele de punctuație
[:necompletat:] [\t] spațiu și TAB
[:spaţiu:] [\t\n\r\f\v] sări peste caractere
[:cntrl:] caractere de control
[:grafic:] [^\t\n\r\f\v] simboluri de sigiliu
[:imprimare:] [^\t\n\r\f\v] simboluri de sigiliu și simboluri de salt

În regex există așa ceva ca:

Lăcomie regex

Voi încerca să o descriu cât mai clar posibil. Să zicem că vrem să găsim totul Etichete HTMLîn unele texte. După ce am localizat problema, dorim să găsim valorile cuprinse între< и >, împreună cu aceleași paranteze. Dar știm că etichetele au lungimi diferite și există cel puțin 50 de etichete. A le enumera pe toate, includerea lor în metasimboluri, este o sarcină care necesită prea mult timp. Dar știm că avem o expresie.* (asterisc punct), care caracterizează orice număr de caractere din rând. Folosind această expresie vom încerca să găsim în text (

Aşa, Cum se creează nivelul RAID 10/50 pe un controler LSI MegaRAID (relevant și pentru: Intel SRCU42x, Intel SRCS16):

) toate valorile între< и >. Ca rezultat, întreaga linie se va potrivi cu această expresie. de ce, pentru că regex este GREEDY și încearcă să captureze ORICE număr de caractere între< и >, respectiv întreaga linie, începând < p>Deci...și sfârșitul ...> va aparține acestei reguli!

Sper că acest exemplu arată clar ce este lăcomia. Pentru a scăpa de această lăcomie, puteți urma următoarea cale:

  • luați în considerare simbolurile Nu corespunzătoare modelului dorit (de exemplu:<[^>]*> pentru cazul de mai sus)
  • scăpați de lăcomie adăugând o definiție a cuantificatorului ca non-lacom:
    • *? - „nu lacom” („leneș”) echivalent *
    • +? - „nu lacom” („leneș”) echivalent +
    • (n,)? - „nu lacom” („leneș”) echivalent (n,)
    • .*? - „nu lacom” („leneș”) echivalent.*

Aș dori să adaug la toate cele de mai sus sintaxa extinsă a expresiilor regulate:

Expresiile regulate din POSIX sunt similare cu sintaxa tradițională Unix, dar cu adăugarea unor metacaractere:

Plus indică faptul că anterior simbol sau grup poate fi repetat una sau mai multe ori. Spre deosebire de asterisc, este necesară cel puțin o repetare.

Semnul întrebării face anterior simbol sau grup opțional. Cu alte cuvinte, în linia corespunzătoare it poate fi absent sau prezent netezi unul dată.

Bară verticală desparte opțiuni alternative expresii regulate. Un caracter specifică două alternative, dar pot fi mai multe dintre ele, doar folosiți mai multe bare verticale. Este important de reținut că acest operator folosește cât mai mult posibil din expresie. Din acest motiv, operatorul alternativ este cel mai des folosit între paranteze.

Utilizarea barelor oblice inverse a fost, de asemenea, eliminată: \(…\) devine (…) și \(…\) devine (…).

Pentru a încheia postarea, voi da câteva exemple de utilizare a expresiei regex:

$ cat text1 1 mere 2 pere 3 banane $ grep p text1 1 mere 2 pere $ grep "pp*" text1 1 mar 2 pere $ cat text1 | grep „l\|n” 1 măr 3 banane $ echo -e „găsește un\n* aici” | grep "\*" * aici $ grep "pl\?.*r" text1 # p, pe liniile în care există un r 2 pear $ grep "a.." text1 # linii cu a urmat de cel puțin 2 caractere 1 apple 3 banana $ grep "" text1 # caută linii care conțin 3 sau p 1 măr 2 pere 3 banane $ echo -e "găsește un\n* aici\nundeva." | grep "[.*]" * aici undeva..nume]$ echo -e "123\n456\n789\n0" | grep "" 123.456.789 $ sed -e "/\(a.*a\)\|\(p.*p\)/s/a/A/g" text1 # înlocuiți a cu A în toate rândurile unde după a vine a sau după p vine p 1 Măr 2 peră 3 bAnAnA *\./ ULTIMUL CUVÂNT./g" Întâi. UN ULTIM CUVÂNT. Acesta este un ULTIM CUVENT.

Salutări, McSim!

Context și sursă: Nu toți cei care trebuie să folosească expresii regulate înțeleg pe deplin cum funcționează sau cum să le creeze. Am aparținut și eu acestui grup - am căutat exemple de expresii regulate potrivite sarcinilor mele, am încercat să le corectez după cum era necesar. Totul s-a schimbat radical pentru mine după ce am citit cartea. Linia de comandă Linux (a doua ediție de internet) autor William E. Shotts, Jr. Stabilește principiile modului în care funcționează expresiile regulate atât de clar încât, după ce am citit, am învățat să le înțeleg, să creez expresii regulate de orice complexitate și acum să le folosesc ori de câte ori este necesar. Acest material este o traducere a părții capitolului dedicată expresiilor regulate. Acest material este destinat începătorilor absoluti care nu înțeleg absolut modul în care funcționează expresiile regulate, dar au o anumită înțelegere a modului în care funcționează expresiile regulate. Sper că acest articol vă va ajuta să faceți aceeași descoperire care m-a ajutat pe mine. Dacă materialul prezentat aici nu conține nimic nou pentru dvs., încercați să vă uitați la articolul „Expresii regulate și comanda grep”, Descrie opțiunile grep mai detaliat, precum și exemple suplimentare.

Cum se folosesc expresiile regulate?

Datele text joacă un rol important în toate Sisteme asemănătoare Unix, cum ar fi Linux. Printre altele, textul este rezultatul programelor de consolă, fișierelor de configurare, rapoarte etc. Expresii regulate sunt (poate) unul dintre cele mai dificile concepte în lucrul cu text, deoarece implică nivel înalt abstracții. Dar timpul petrecut studiul lor va fi mai mult decât răsplătit. Dacă știi să folosești expresiile regulate, poți face lucruri uimitoare, deși valoarea lor completă poate să nu fie imediat evidentă.

Acest articol va analiza utilizarea expresiilor regulate împreună cu comanda grep. Dar utilizarea lor nu se limitează la aceasta: expresiile regulate sunt suportate de alte comenzi Linux, multe limbaje de programare, folosite în configurare (de exemplu, în setările regulii mod_rewrite din Apache), precum și unele programe cu interfata grafica vă permit să setați reguli pentru căutare/copiere/ștergere cu suport pentru expresii regulate. Chiar și în populare program de birouÎn Microsoft Word, puteți utiliza expresii obișnuite și caractere wildcard pentru a căuta și înlocui text.

Ce sunt expresiile regulate?

În termeni simpli, o expresie regulată este simbol, o notație simbolică a modelului care este căutat în text. Expresiile regulate sunt susținute de multe instrumente linie de comandăși majoritatea limbajelor de programare și sunt folosite pentru a facilita rezolvarea problemelor legate de manipularea textului. Cu toate acestea, de parcă complexitatea lor nu este suficientă pentru noi, nu toate expresiile regulate sunt create egale. Acestea variază ușor de la un instrument la altul și de la un limbaj de programare la altul. Pentru discuția noastră, ne vom limita la expresiile regulate descrise în standardul POSIX (care va acoperi majoritatea instrumentelor de linie de comandă), spre deosebire de multe limbaje de programare (mai ales Perl), care folosesc seturi de notații ceva mai mari și mai bogate. .

grep

Programul principal pe care îl vom folosi pentru expresiile regulate este vechiul nostru prieten, . Numele „grep” provine de fapt de la expresia „printare a expresiei regulate globale”, așa că putem vedea că grep are ceva de-a face cu expresiile regulate. În esență, grep caută în fișierele text text care se potrivește cu o expresie regulată specificată și imprimă la ieșirea standard orice linie care conține o potrivire.

grep poate căuta textul primit în intrarea standard, de exemplu:

ls /usr/bin | fermoar grep

Această comandă va lista fișierele din directorul /usr/bin ale căror nume conțin subșirul „zip”.

Programul grep poate căuta text în fișiere.

Sintaxă generală de utilizare:

Grep [opțiuni] regex [fișier...]

  • regex este o expresie regulată.
  • [fişier…]- unul sau mai multe fișiere care vor fi căutate folosind o expresie regulată.

[Opțiuni] și [fișier...] pot lipsi.

Lista celor mai frecvent utilizate opțiuni grep:

Opţiune Descriere
-i Ignora majusculele. Nu faceți diferența între caracterele mari și cele mici. De asemenea, puteți seta opțiunea --ignora-majuscule.
-v Inversați potrivirea. În mod normal, grep va imprima liniile care conțin potrivirea. Această opțiune face ca grep să imprime fiecare linie care nu conține o potrivire. De asemenea, puteți utiliza --invers-potrivire.
-c Tipăriți numărul de potriviri (sau nepotriviri dacă este specificată opțiunea -v) în locul liniilor în sine. De asemenea, puteți specifica opțiunea --conta.
-l În loc de șirurile în sine, tipăriți numele fiecărui fișier care conține potrivirea. Poate fi specificat cu opțiunea --fișiere-cu-potriviri.
-L Ca opțiune -l, dar imprimă numai nume de fișiere care nu conțin potriviri. Un alt nume de opțiune --fișiere-fără potrivire.
-n Adăugarea unui număr de linie în fișier la începutul fiecărei linii potrivite. Un alt nume de opțiune --line-number.
-h Pentru a căuta mai multe fișiere, suprimați ieșirea numelui fișierului. De asemenea, puteți specifica opțiunea --no-filename.

Pentru a explora grep mai pe deplin, haideți să creăm câteva fișiere text pe care să le căutați:

Ls /bin > dirlist-bin.txt ls /usr/bin > dirlist-usr-bin.txt ls /sbin > dirlist-sbin.txt ls /usr/sbin > dirlist-usr-sbin.txt ls dirlist*.txt dirlist -bin.txt dirlist-sbin.txt dirlist-usr-bin.txt dirlist-usr-sbin.txt

Putem face o căutare simplă prin lista noastră de fișiere, astfel:

Grep bzip dirlist*.txt dirlist-bin.txt:bzip2 dirlist-bin.txt:bzip2recover

În acest exemplu, grep caută în toate fișierele listate șirul bzip și găsește două potriviri, ambele în fișierul dirlist-bin.txt. Dacă ne interesează doar lista de fișiere care conțin potrivirile, și nu șirurile care se potrivesc în sine, putem specifica opțiunea -l:

Grep -l bzip dirlist*.txt dirlist-bin.txt

În schimb, dacă am dori să vedem doar o listă de fișiere care nu conțineau potriviri, am putea face acest lucru:

Grep -L bzip dirlist*.txt dirlist-sbin.txt dirlist-usr-bin.txt dirlist-usr-sbin.txt

Dacă nu există nicio ieșire, înseamnă că nu au fost găsite fișiere care îndeplinesc condițiile.

Metacaractere și literale

Deși poate să nu pară evident, căutările noastre grep folosesc întotdeauna expresii regulate, deși sunt foarte simple. Expresia regulată „bzip” înseamnă că va avea loc o potrivire (adică linia va fi considerată o potrivire) numai dacă linia din fișier conține cel puțin patru caractere și că caracterele „b”, „z” sunt undeva în linie , „i” și „p” sunt în această ordine, fără alte caractere între ele. Caracterele din șirul „bzip” sunt literali, adică simboluri literale, pentru că ele corespund lor înșiși. Pe lângă literale, pot include și expresiile regulate metacaracterele, care sunt folosite pentru a specifica potriviri mai complexe. Metacaracterele expresiei regulate constau din următoarele:

^ $ . { } - ? * + () | \

Toate celelalte personaje sunt considerate literale. Caracterul backslash poate avea semnificații diferite. Este folosit în mai multe cazuri pentru a crea meta-secvențe, și, de asemenea, permite metacaracterelor să fie evadate și tratate nu ca metacaractere, ci ca literale.

Nota: după cum putem vedea, multe metacaractere ale expresiilor regulate sunt, de asemenea, caractere cu semnificație de shell (performing expansion). Când specificați o expresie regulată care conține metacaractere de linie de comandă, este imperativ ca aceasta să fie închisă între ghilimele, altfel shell-ul le va interpreta în felul său și va întrerupe comanda.

Orice personaj

Primul metacaracter cu care ne vom începe cunoștința este simbol punct, care înseamnă „orice personaj”. Dacă îl includem într-o expresie regulată, atunci se va potrivi cu orice caracter pentru acea poziție a caracterului. Exemplu:

Grep -h „.zip” dirlist*.txt bunzip2 bzip2 bzip2recover gunzip gzip funzip gpg-zip mzip p7zip preunzip prezip prezip-bin unzip unzipsfx

Am căutat orice șir în fișierele noastre care se potrivea cu expresia obișnuită „.zip”. Există câteva puncte interesante de remarcat despre rezultate. Rețineți că program zip nu a fost găsit. Acest lucru se datorează faptului că includerea metacaracterului punct în expresia noastră regulată a crescut lungimea necesară pentru o potrivire la patru caractere și, deoarece numele „zip” conține doar trei, nu se potrivește. De asemenea, dacă oricare dintre fișierele din listele noastre conținea o extensie de fișier .zip, ar fi, de asemenea, considerate eligibile, deoarece caracterul punct din extensia de fișier se califică și pentru condiția „orice caracter”.

Ancore

Simbol caret ( ^ ) și semnul dolarului ( $ ) sunt considerate în expresiile regulate ancore. Aceasta înseamnă că provoacă o potrivire numai dacă expresia regulată este găsită la începutul șirului ( ^ ) sau la sfârșitul liniei ( $ ):

Grep -h „^zip” dirlist*.txt zip zipcloak zipdetails zipgrep zipinfo zipnote zipsplit grep -h „zip$” dirlist*.txt gunzip gzip funzip gpg-zip mzip p7zip preunzip prezip unzip zip grep$ -h "^zip list *.txt zip

Aici am căutat în listele de fișiere șirul „zip” situat la începutul liniei, la sfârșitul rândului și, de asemenea, într-o linie unde ar fi atât la început, cât și la sfârșit (adică întreaga linie ar conține doar „zip” ). Vă rugăm să rețineți că expresia regulată „ ^$ " (începutul și sfârșitul fără nimic între) se vor potrivi cu liniile goale.

O scurtă digresiune: un asistent pentru cuvinte încrucișate

Chiar și cu limitatul nostru în acest moment Cu cunoștințele expresiilor regulate putem face ceva util.

Dacă ați făcut vreodată cuvinte încrucișate, ați trebuit să rezolvați probleme precum „care este cuvântul cu cinci litere în care a treia literă este un „j” și ultima literă este un „r”, ceea ce înseamnă...”. Această întrebare te poate pune pe gânduri. Știai că în sistem Linux ai un dictionar? Și el este. Căutați în directorul /usr/share/dict, puteți găsi unul sau mai multe dicționare acolo. Dicționarele postate acolo sunt pur și simplu liste lungi de cuvinte, câte unul pe rând, aranjate în ordine alfabetică. Pe sistemul meu, fișierul dicționar conține 99171 de cuvinte. Pentru a căuta posibile răspunsuri la întrebarea de cuvinte încrucișate de mai sus, putem face acest lucru:

Grep -i „^..j.r$” /usr/share/dict/american-english Major major

Folosind această expresie regulată, putem găsi toate cuvintele din fișierul nostru dicționar care au cinci litere, au un „j” în a treia poziție și un „r” în ultima poziție.

Exemplul a folosit un fișier de dicționar englezesc, deoarece este prezent în sistem în mod implicit. După ce ați descărcat anterior dicționarul corespunzător, puteți efectua căutări similare folosind cuvinte în chirilic sau orice alte caractere.

Expresii paranteze și clase de caractere

Pe lângă potrivirea oricărui caracter la o anumită poziție în expresia noastră regulată, folosim și expresii între paranteze drepte, putem seta o potrivire la un singur caracter din setul de caractere specificat. Cu expresii paranteze, putem specifica un set de caractere care să se potrivească (inclusiv caractere care altfel ar fi interpretate ca metacaractere). În acest exemplu, folosind un set de două caractere:

Grep -h „zip” dirlist*.txt bzip2 bzip2recover gzip

vom găsi orice linii care conțin șirurile „bzip” sau „gzip”.

Setul poate conține orice număr de caractere, iar metacaracterele își pierd semnificația specială atunci când sunt plasate între paranteze drepte. Cu toate acestea, există două cazuri în care metacaracterele folosite între paranteze pătrate au semnificații diferite. Prima este trăsura ( ^ ), care este folosit pentru a indica negația; a doua este o liniuță ( - ), care este folosit pentru a specifica o serie de caractere.

Negare

Dacă primul caracter al expresiei dintre paranteze pătrate este un accent ( ^ ), apoi caracterele rămase sunt luate ca un set de caractere care nu ar trebui să fie prezente la poziția dată a caracterului. Să facem asta schimbând exemplul nostru anterior:

Grep -h „[^bg]zip” dirlist*.txt bunzip2 gunzip funzip gpg-zip mzip p7zip preunzip prezip prezip-bin unzip unzipsfx

Cu negația activată, obținem o listă de fișiere care conțin șirul „zip” precedat de orice alt caracter decât „b” sau „g”. Vă rugăm să rețineți că zip nu a fost găsit. Un set de caractere negat necesită încă un caracter la poziția dată, dar caracterul nu trebuie să fie membru al setului de caractere negat.

Caracterul caret este negat numai dacă este primul caracter dintr-o expresie între paranteze; în caz contrar, își pierde scopul special și devine un simbol obișnuit din set.

Gama de caractere tradiționale

Dacă am dori să construim o expresie regulată care să găsească fiecare fișier din lista noastră care începe cu o literă majusculă, am putea face următoarele:

Grep -h „^” dirlist*.txt MAKEDEV GET HEAD POST VBoxClient X X11 Xorg ModemManager NetworkManager VBoxControl VBoxService

Ideea este că punem toate cele 26 de majuscule în expresie între paranteze pătrate. Dar ideea de a le tipări pe toate nu inspiră entuziasm, așa că există o altă modalitate:

Grep -h „^” dirlist*.txt

Folosind un interval de trei caractere, putem scurta intrarea de 26 de litere. Puteți exprima orice interval de caractere în acest fel, inclusiv mai multe intervale simultan, cum ar fi această expresie, care se potrivește cu toate numele fișierelor care încep cu litere și cifre:

Grep -h „^” dirlist*.txt

În intervalele de caractere vedem că caracterul liniuță este tratat într-un mod special, deci cum putem include caracterul liniuță într-o expresie între paranteze pătrate? Făcându-l primul personaj din expresie. Să ne uităm la două exemple:

Grep -h "" dirlist*.txt

Aceasta se va potrivi cu fiecare nume de fișier care conține o literă majusculă. În acest caz:

Grep -h „[-AZ]” dirlist*.txt

se va potrivi cu fiecare nume de fișier care conține o liniuță sau un „A” majuscul sau un „Z” majuscul.

Pentru a procesa pe deplin textele în scripturile bash folosind sed și awk, trebuie doar să înțelegeți expresiile regulate. Implementările acestui instrument cel mai util pot fi găsite literalmente peste tot și, deși toate expresiile regulate sunt structurate într-un mod similar și se bazează pe aceleași idei, lucrul cu ele în medii diferite are anumite caracteristici. Aici vom vorbi despre expresiile regulate care sunt potrivite pentru utilizare în scripturile liniei de comandă Linux.

Acest material este conceput ca o introducere în expresiile regulate, destinate celor care ar putea să nu fie complet conștienți de ceea ce sunt acestea. Deci, să începem de la bun început.

Ce sunt expresiile regulate

Mulți oameni, când văd pentru prima dată expresii obișnuite, cred imediat că se uită la un amestec fără sens de caractere. Dar acest lucru, desigur, este departe de a fi cazul. Aruncă o privire la acest regex, de exemplu


În opinia noastră, chiar și un începător absolut va înțelege imediat cum funcționează și de ce este nevoie de el :) Dacă nu înțelegeți prea bine, citiți mai departe și totul va fi la locul său.
O expresie regulată este un model pe care programe precum sed sau awk îl folosesc pentru a filtra textul. Șabloanele folosesc caractere ASCII obișnuite care se reprezintă și așa-numitele metacaractere care joacă un rol special, de exemplu, permițând referirea la anumite grupuri de caractere.

Tipuri de expresii regulate

Implementări de expresii regulate în diverse medii, cum ar fi limbaje de programare precum Java, Perl și Python, în instrumente Linux precum sed, awk și grep, au anumite caracteristici. Aceste caracteristici depind de așa-numitele motoare de expresie regulată, care interpretează tiparele.
Linux are două motoare de expresii regulate:
  • Un motor care acceptă standardul POSIX Basic Regular Expression (BRE).
  • Un motor care acceptă standardul POSIX Extended Regular Expression (ERE).
Majoritatea utilităților Linux se conformează cel puțin standardului POSIX BRE, dar unele utilități (inclusiv sed) înțeleg doar un subset al standardului BRE. Unul dintre motivele acestei limitări este dorința de a face astfel de utilitare cât mai rapid posibil în procesarea textului.

Standardul POSIX ERE este adesea implementat în limbaje de programare. Vă permite să utilizați un număr mare de instrumente atunci când dezvoltați expresii regulate. De exemplu, acestea ar putea fi secvențe speciale de caractere pentru modele utilizate frecvent, cum ar fi căutarea de cuvinte individuale sau seturi de numere în text. Awk acceptă standardul ERE.

Există multe modalități de a dezvolta expresii regulate, în funcție atât de opinia programatorului, cât și de caracteristicile motorului pentru care sunt create. Nu este ușor să scrii expresii regulate universale pe care orice motor le poate înțelege. Prin urmare, ne vom concentra pe expresiile regulate cele mai frecvent utilizate și ne vom uita la caracteristicile implementării lor pentru sed și awk.

Expresii regulate POSIX BRE

Poate cel mai simplu model BRE este o expresie regulată pentru căutarea apariției exacte a unei secvențe de caractere în text. Iată cum arată căutarea unui șir în sed și awk:

$ echo „Acesta este un test” | sed -n "/test/p" $ echo "Acesta este un test" | awk "/test/(printează $0)"

Găsirea textului după model în sed


Găsirea textului după model în awk

Este posibil să observați că căutarea unui model dat este efectuată fără a lua în considerare locația exactă a textului în linie. În plus, numărul de apariții nu contează. După ce expresia regulată găsește textul specificat oriunde în șir, șirul este considerat adecvat și este transmis pentru procesare ulterioară.

Când lucrați cu expresii regulate, trebuie să țineți cont de faptul că acestea sunt sensibile la majuscule și minuscule:

$ echo „Acesta este un test” | awk "/Test/(printează $0)" $ echo "Acesta este un test" | awk "/test/(printează $0)"

Expresiile regulate sunt sensibile la majuscule

Prima expresie regulată nu a găsit nicio potrivire deoarece cuvântul „test”, care începe cu majusculă, nu apare în text. Al doilea, configurat să caute un cuvânt scris cu majuscule, a găsit o linie potrivită în flux.

În expresiile regulate, puteți folosi nu numai litere, ci și spații și numere:

$ echo „Acesta este din nou un test 2” | awk "/test 2/(printează $0)"

Găsirea unei porțiuni de text care conține spații și numere

Spațiile sunt tratate ca caractere regulate de către motorul de expresii regulate.

Personaje speciale

Când folosiți diferite caractere în expresiile regulate, există câteva lucruri de luat în considerare. Da, sunt unele caractere speciale, sau metacaractere, a căror utilizare într-un șablon necesită o abordare specială. Iată-le:

.*^${}\+?|()
Dacă unul dintre ele este necesar în șablon, acesta va trebui să fie eliminat folosind o bară oblică inversă (backslash) - \ .

De exemplu, dacă trebuie să găsiți un semn dolar în text, trebuie să îl includeți în șablon, precedat de un caracter de escape. Să presupunem că există un fișier myfile cu următorul text:

Sunt 10$ pe buzunarul meu
Semnul dolarului poate fi detectat folosind acest model:

$awk „/\$/(printează $0)” fișierul meu

Utilizarea unui caracter special într-un model

În plus, bara oblică inversă este, de asemenea, un caracter special, așa că dacă trebuie să-l folosești într-un model, va trebui să fie și evadat. Arată ca două slashuri care urmează:

$ echo „\ este un caracter special” | awk "/\\/(printează $0)"

Scăpând de o bară oblică inversă

Deși bara oblică nu este inclusă în lista de caractere speciale de mai sus, încercarea de a o folosi într-o expresie regulată scrisă pentru sed sau awk va avea ca rezultat o eroare:

$ echo "3 / 2" | awk "///(printează $0)"

Utilizarea incorectă a barei oblice într-un model

Dacă este necesar, trebuie să fie scăpat și:

$ echo "3 / 2" | awk "/\//(printează $0)"

Scăpând de o bară oblică înainte

Simboluri de ancorare

Există două caractere speciale pentru a lega un model la începutul sau la sfârșitul unui șir de text. Caracterul cap - ^ vă permite să descrieți secvențe de caractere care se află la începutul liniilor de text. Dacă modelul pe care îl căutați este în altă parte în șir, expresia regulată nu va răspunde la el. Utilizarea acestui simbol arată astfel:

$ echo „Bine ați venit pe site-ul likegeeks” | awk „/^likegeeks/(print $0)” $ echo „site-ul web likegeeks” | awk "/^likegeeks/(printează $0)"

Găsirea unui model la începutul unui șir

Caracterul ^ este conceput pentru a căuta un model la începutul unei linii, în timp ce se ia în considerare și cazul caracterelor. Să vedem cum afectează acest lucru procesarea unui fișier text:

$awk "/^this/(print $0)" fișierul meu


Găsirea unui model la începutul unei linii în text dintr-un fișier

Când utilizați sed, dacă plasați un capac undeva în interiorul modelului, acesta va fi tratat ca orice alt caracter obișnuit:

$ echo „Acesta ^ este un test” | sed -n "/s ^/p"

Cap nu la începutul modelului în sed

În awk, atunci când utilizați același șablon, acest caracter trebuie să fie eliminat:

$ echo „Acesta ^ este un test” | awk "/s\^/(printează $0)"

Acoperiți nu la începutul șablonului în awk

Ne-am dat seama de căutarea fragmentelor de text situate la începutul unei linii. Ce se întâmplă dacă trebuie să găsiți ceva situat la sfârșitul unei linii?

Semnul dolarului - $, care este caracterul ancoră pentru sfârșitul liniei, ne va ajuta în acest sens:

$ echo „Acesta este un test” | awk "/test$/(printează $0)"

Găsirea textului la sfârșitul unui rând

Puteți utiliza ambele simboluri de ancoră în același șablon. Să procesăm fișierul myfile, al cărui conținut este prezentat în figura de mai jos, folosind următoarea expresie regulată:

$ awk "/^acesta este un test$/(printează $0)" fișierul meu


Un model care folosește caractere speciale pentru a începe și a încheia o linie

După cum puteți vedea, șablonul a răspuns doar la o linie care corespundea pe deplin secvenței date de caractere și locației acestora.

Iată cum puteți filtra liniile goale folosind caractere de ancorare:

$awk "!/^$/(printează $0)" fișierul meu
În acest șablon am folosit un simbol de negație, un semn de exclamare - ! . Folosind acest model, se caută linii care nu conțin nimic între începutul și sfârșitul liniei și, datorită semnului exclamării, sunt tipărite doar liniile care nu se potrivesc cu acest model.

Simbol punct

Punctul este folosit pentru a se potrivi cu orice caracter, cu excepția caracterului nou linie. Să transmitem fișierul myfile acestei expresii regulate, al cărei conținut este prezentat mai jos:

$awk "/.st/(printează $0)" fișierul meu


Folosirea unui punct în expresiile regulate

După cum se poate observa din datele de ieșire, doar primele două linii din fișier se potrivesc cu modelul, deoarece conțin secvența de caractere „st” precedate de un alt caracter, în timp ce a treia linie nu conține o secvență adecvată, iar a patra îl are, dar se află chiar la începutul liniei.

Clasele de caractere

Un punct se potrivește cu orice caracter, dar ce se întâmplă dacă doriți să fiți mai flexibil în limitarea setului de caractere pe care îl căutați? În această situație, puteți utiliza clase de caractere.

Datorită acestei abordări, puteți organiza o căutare pentru orice caracter dintr-un set dat. Pentru a descrie o clasă de caractere, se folosesc paranteze drepte:

$awk "/th/(printează $0)" fișierul meu


Descrierea unei clase de caractere într-o expresie regulată

Aici căutăm o secvență de caractere „th” precedate de un caracter „o” sau un caracter „i”.

Clasele sunt foarte utile atunci când căutați cuvinte care pot începe fie cu o literă mare, fie cu minuscule:

$ echo „acesta este un test” | awk "/el este un test/(printează $0)" $ echo "Acesta este un test" | awk "/el este un test/(printează $0)"

Căutați cuvinte care pot începe cu o literă mică sau mare

Clasele de caractere nu se limitează la litere. Alte simboluri pot fi folosite aici. Este imposibil să spunem în avans în ce situație vor fi necesare clase - totul depinde de problema care se rezolvă.

Negarea claselor de caractere

Clasele de caractere pot fi folosite și pentru a rezolva problema inversă descrisă mai sus. Și anume, în loc să cauți simboluri incluse într-o clasă, poți organiza o căutare pentru tot ceea ce nu este inclus în clasă. Pentru a obține acest comportament de expresie regulată, trebuie să plasați un semn ^ în fața listei de caractere ale clasei. Arata cam asa:

$ awk „/[^oi]th/(print $0)” fișierul meu


Găsirea personajelor care nu sunt într-o clasă

În acest caz, vor fi găsite secvențe de caractere „th” care nu sunt precedate nici de „o”, nici de „i”.

Intervalele de caractere

În clasele de caractere, puteți descrie intervale de caractere folosind liniuțe:

$awk "/st/(printează $0)" fișierul meu


Descrierea unei game de caractere dintr-o clasă de caractere

ÎN în acest exemplu Expresia regulată răspunde unei secvențe de caractere „st” precedate de orice caracter situat, în ordine alfabetică, între caracterele „e” și „p”.

Intervalele pot fi create și din numere:

$ echo „123” | awk "//" $ echo "12a" | awk "//"

Expresie regulată pentru a găsi orice trei numere

O clasă de caractere poate include mai multe intervale:

$awk "/st/(printează $0)" fișierul meu


O clasă de caractere formată din mai multe intervale

Această expresie regulată va găsi toate secvențele de „st” precedate de caractere din intervalele a-fși m-z.

Clase de caractere speciale

BRE are clase de caractere speciale care pot fi folosite la scrierea expresiilor regulate:
  • [[:alpha:]] - se potrivește cu orice caracter alfabetic, scris cu litere mari sau mici.
  • [[:alnum:]] - se potrivește cu orice caracter alfanumeric, și anume caractere din intervalele 0-9 , A-Z , a-z .
  • [[:blank:]] - se potrivește cu un spațiu și un caracter tabulator.
  • [[:digit:]] - orice caracter cifră de la 0 la 9.
  • [[:upper:]] - caractere alfabetice în majuscule- A-Z.
  • [[:lower:]] - caractere alfabetice mici - a-z .
  • [[:print:]] - se potrivește cu orice caracter imprimabil.
  • [[:punct:]] - se potrivește cu semnele de punctuație.
  • [[:space:]] - caractere cu spații albe, în special - spațiu, tab, caractere NL, FF, VT, CR.
Puteți folosi clase speciale în șabloane ca acesta:

$ echo "abc" | awk „/[[:alpha:]]/(printează $0)” $ echo „abc” | awk "/[[:digit:]]/(printează $0)" $ echo "abc123" | awk "/[[:digit:]]/(printează $0)"


Clase de caractere speciale în expresiile regulate

Simbol stea

Dacă plasați un asterisc după un caracter dintr-un model, aceasta va însemna că expresia regulată va funcționa dacă caracterul apare în șir de orice număr de ori - inclusiv situația în care caracterul este absent în șir.

$ echo "test" | awk "/tes*t/(print $0)" $ echo "tessst" | awk "/tes*t/(printează $0)"


Utilizarea caracterului * în expresiile regulate

Acest wildcard este de obicei folosit pentru cuvintele care sunt scrise greșit în mod constant sau pentru cuvintele care au diferite ortografii corecte:

$ echo „Îmi place culoarea verde” | awk "/colou*r/(print $0)" $ echo "Îmi place culoarea verde" | awk "/color*r/(printează $0)"

Găsirea unui cuvânt cu ortografii diferite

În acest exemplu, aceeași expresie regulată răspunde atât cuvântului „culoare”, cât și cuvântului „culoare”. Acest lucru se datorează faptului că caracterul „u”, urmat de un asterisc, poate fi fie absent, fie poate apărea de mai multe ori la rând.

O altă caracteristică utilă care vine de la simbolul asterisc este combinarea acestuia cu un punct. Această combinație permite expresiei regulate să răspundă la orice număr de caractere:

$ awk "/this.*test/(print $0)" fișierul meu


Un șablon care răspunde la orice număr de caractere

În acest caz, nu contează câte și ce caractere sunt între cuvintele „acest” și „test”.

Asteriscul poate fi folosit și cu clase de caractere:

$ echo „st” | awk "/s*t/(print $0)" $ echo "sat" | awk "/s*t/(print $0)" $ echo "set" | awk "/s*t/(printează $0)"


Utilizarea unui asterisc cu clase de caractere

În toate cele trei exemple, expresia regulată funcționează deoarece asteriscul după clasa de caractere înseamnă că dacă se găsește orice număr de caractere „a” sau „e” sau dacă nu se găsește niciunul, șirul se va potrivi cu modelul dat.

POSIX ERE expresii regulate

Șabloanele POSIX ERE pe care le acceptă unele utilitare Linux pot conține caractere suplimentare. După cum am menționat deja, awk acceptă acest standard, dar sed nu.

Aici vom analiza cele mai frecvent utilizate simboluri în modelele ERE, care vă vor fi utile atunci când vă creați propriile expresii regulate.

▍Semn de întrebare

Un semn de întrebare indică faptul că caracterul precedent poate apărea o dată sau deloc în text. Acest personaj este unul dintre metacaracterele repetate. Iată câteva exemple:

$ echo "tet" | awk "/tes?t/(print $0)" $ echo "test" | awk "/tes?t/(print $0)" $ echo "testest" | awk "/tes?t/(printează $0)"


Semnul întrebării în expresiile regulate

După cum puteți vedea, în al treilea caz litera „s” apare de două ori, astfel încât expresia regulată nu răspunde cuvântului „testst”.

Semnul întrebării poate fi folosit și cu clase de caractere:

$ echo "tst" | awk "/t?st/(print $0)" $ echo "test" | awk "/t?st/(print $0)" $ echo "gust" | awk "/t?st/(print $0)" $ echo "taest" | awk "/t?st/(print $0)" $ echo "teest" | awk "/t?st/(printează $0)"


Semn de întrebare și clase de caractere

Dacă nu există caractere din clasă în linie, sau unul dintre ele apare o dată, expresia regulată funcționează, dar de îndată ce două caractere apar în cuvânt, sistemul nu mai găsește o potrivire pentru modelul din text.

▍Simbol Plus

Caracterul plus din model indică faptul că expresia regulată se va potrivi cu ceea ce caută dacă caracterul precedent apare o dată sau de mai multe ori în text. Cu toate acestea, această construcție nu va reacționa la absența unui simbol:

$ echo "test" | awk "/te+st/(print $0)" $ echo "teest" | awk "/te+st/(print $0)" $ echo "tst" | awk "/te+st/(printează $0)"


Simbolul plus în expresiile regulate

În acest exemplu, dacă nu există un caracter „e” în cuvânt, motorul de expresii regulate nu va găsi potriviri cu modelul din text. Simbolul plus funcționează și cu clasele de caractere - în acest fel este similar cu un asterisc și un semn de întrebare:

$ echo "tst" | awk „/t+st/(printează $0)” $ echo „test” | awk „/t+st/(printează $0)” $ echo „testare” | awk „/t+st/(printează $0)” $ echo „teeast” | awk "/t+st/(printează $0)"


Plus semne și clase de caractere

În acest caz, dacă linia conține vreun caracter din clasă, textul va fi considerat că se potrivește cu modelul.

▍Acolade

Acoladele, care pot fi folosite în modelele ERE, sunt similare cu simbolurile discutate mai sus, dar vă permit să specificați mai precis numărul necesar de apariții ale simbolului care le precede. Puteți specifica o restricție în două formate:
  • n - un număr care specifică numărul exact de apariții căutate
  • n, m sunt două numere care sunt interpretate după cum urmează: „de cel puțin n ori, dar nu mai mult de m”.
Iată exemple de prima opțiune:

$ echo "tst" | awk "/te(1)st/(print $0)" $ echo "test" | awk "/te(1)st/(print $0)"

Acolade în modele, căutând numărul exact de apariții

În versiunile mai vechi de awk trebuia să utilizați opțiunea de linie de comandă --re-interval pentru a face programul să recunoască intervalele în expresiile regulate, dar în versiunile mai noi acest lucru nu este necesar.

$ echo "tst" | awk "/te(1,2)st/(print $0)" $ echo "test" | awk "/te(1,2)st/(print $0)" $ echo "teest" | awk "/te(1,2)st/(print $0)" $ echo "teeest" | awk "/te(1,2)st/(printează $0)"


Spațiere specificată în acolade

În acest exemplu, caracterul „e” trebuie să apară de 1 sau de 2 ori pe linie, apoi expresia regulată va răspunde textului.

Acoladele pot fi folosite și cu clase de caractere. Principiile pe care le cunoașteți deja se aplică aici:

$ echo "tst" | awk "/t(1,2)st/(printează $0)" $ echo "test" | awk „/t(1,2)st/(printează $0)” $ echo „test” | awk "/t(1,2)st/(printează $0)" $ echo "teeast" | awk "/t(1,2)st/(printează $0)"


Acolade și clase de caractere

Șablonul va reacționa la text dacă conține caracterul „a” sau caracterul „e” o dată sau de două ori.

▍Simbol logic „sau”.

Simbol | - o bară verticală înseamnă un „sau” logic în expresiile regulate. Atunci când procesează o expresie regulată care conține mai multe fragmente separate printr-un astfel de semn, motorul va considera potrivit textul analizat dacă se potrivește cu oricare dintre fragmente. Iată un exemplu:

$ echo „Acesta este un test” | awk „/test|examen/(printează $0)” $ echo „Acesta este un examen” | awk "/test|examen/(printează $0)" $ echo "Acesta este altceva" | awk "/test|examen/(printați $0)"


„sau” logic în expresiile regulate

În acest exemplu, expresia regulată este configurată pentru a căuta în text cuvintele „test” sau „examen”. Vă rugăm să rețineți că între fragmentele șablonului și simbolul care le separă | nu ar trebui să existe spații.

Fragmentele de expresie regulată pot fi grupate folosind paranteze. Dacă grupați o anumită secvență de caractere, aceasta va fi percepută de sistem ca un personaj obișnuit. Adică, de exemplu, i se pot aplica metacaractere repetate. Cam asa arata:

$ echo „Like” | awk "/Like(Geeks)?/(print $0)" $ echo "LikeGeeks" | awk "/Like(Geeks)?/(print $0)"


Gruparea fragmentelor de expresie regulată

În aceste exemple, cuvântul „Geeks” este cuprins între paranteze, urmat de un semn de întrebare. Amintiți-vă că un semn de întrebare înseamnă „0 sau 1 repetiție”, astfel încât expresia obișnuită va răspunde atât la șirul „Like”, cât și la șirul „LikeGeeks”.

Exemple practice

Acum că am acoperit elementele de bază ale expresiilor regulate, este timpul să facem ceva util cu ele.

▍Numărarea numărului de fișiere

Să scriem un script bash care numără fișierele aflate în directoarele în care sunt scrise variabila de mediu CALE. Pentru a face acest lucru, va trebui mai întâi să generați o listă de căi de directoare. Să facem asta folosind sed, înlocuind punctele cu spații:

$ echo $PATH | sed "s/:/ /g"
Comanda înlocuire acceptă expresii regulate ca modele pentru căutarea textului. În acest caz, totul este extrem de simplu, căutăm simbolul două puncte, dar nimeni nu ne deranjează să folosim altceva aici - totul depinde de sarcina specifică.
Acum trebuie să parcurgeți lista rezultată într-o buclă și să efectuați acțiunile necesare pentru a număra numărul de fișiere. Schema generala scenariul va fi astfel:

Mypath=$(echo $PATH | sed "s/://g") pentru directorul din $mypath do done
Acum să scriem textul complet al scriptului, folosind comanda ls pentru a obține informații despre numărul de fișiere din fiecare director:

#!/bin/bash mypath=$(echo $PATH | sed "s/:/ /g") count=0 pentru directorul din $mypath do check=$(ls $directory) pentru elementul din $check do count=$ [ $count + 1 ] done echo "$directory - $count" count=0 done
Când rulați scriptul, se poate dovedi că unele directoare din PATH nu există, totuși, acest lucru nu îl va împiedica să numere fișiere din directoarele existente.


Numărarea fișierelor

Valoarea principală a acestui exemplu este că, folosind aceeași abordare, puteți rezolva mult mai multe sarcini complexe. Care depind exact de nevoile tale.

▍Verificarea adreselor de e-mail

Există site-uri web cu colecții uriașe de expresii regulate care vă permit să verificați adresele e-mail, numere de telefon, și așa mai departe. Cu toate acestea, una este să iei ceva gata făcut și alta este să creezi singur ceva. Deci, să scriem o expresie obișnuită pentru a verifica adresele de e-mail. Să începem cu analiza datelor sursă. Iată, de exemplu, o anumită adresă:

[email protected]
Numele de utilizator, numele de utilizator, poate consta din caractere alfanumerice și alte caractere. Și anume, acesta este un punct, o liniuță, o liniuță de subliniere, un semn plus. Numele de utilizator este urmat de un semn @.

Înarmați cu aceste cunoștințe, să începem asamblarea expresiei regulate din partea stângă, care este folosită pentru a verifica numele de utilizator. Iată ce avem:

^(+)@
Această expresie regulată poate fi citită după cum urmează: „Rândul trebuie să înceapă cu cel puțin un caracter dintre cei din grupul specificat între paranteze drepte, urmat de un semn @.”

Acum - coada de nume de gazdă - nume de gazdă. Aici se aplică aceleași reguli ca și pentru numele de utilizator, așa că șablonul pentru acesta va arăta astfel:

(+)
Numele de domeniu de nivel superior este supus unor reguli speciale. Pot exista doar caractere alfabetice, dintre care trebuie să existe cel puțin două (de exemplu, astfel de domenii conțin de obicei un cod de țară) și nu mai mult de cinci. Toate acestea înseamnă că șablonul pentru verificarea ultimei părți a adresei va fi astfel:

\.({2,5})$
Puteți citi astfel: „Mai întâi trebuie să fie un punct, apoi 2 până la 5 caractere alfabetice, iar după aceea linia se termină”.

După ce am pregătit șabloane pentru părți individuale ale expresiei regulate, să le punem împreună:

^(+)@(+)\.({2,5})$
Acum nu mai rămâne decât să testăm ce s-a întâmplat:

$ echo " [email protected]" | awk "/^(+)@(+)\.((2,5))$/(printează $0)" $ echo " [email protected]" | awk "/^(+)@(+)\.((2,5))$/(printează $0)"


Validarea unei adrese de e-mail folosind expresii regulate

Faptul că textul transmis către awk este afișat pe ecran înseamnă că sistemul l-a recunoscut ca adresă de e-mail.

Rezultate

Dacă expresia obișnuită pentru verificarea adreselor de e-mail pe care ați întâlnit-o chiar la începutul articolului părea complet de neînțeles atunci, sperăm că acum nu mai arată ca un set de caractere fără sens. Dacă acest lucru este într-adevăr așa, înseamnă acest materialși-a îndeplinit scopul. De fapt, expresiile regulate sunt un subiect pe care îl poți studia toată viața, dar chiar și puținul pe care l-am abordat te poate ajuta deja să scrii scripturi care procesează texte destul de avansate.

În această serie de materiale am arătat de obicei foarte exemple simple scripturi bash care constau literalmente din mai multe linii. Data viitoare ne uităm la ceva mai mare.

Dragi cititori! Folosiți expresii regulate atunci când procesați text în scripturile din linia de comandă?

Una dintre cele mai utile și bogate în funcții comenzi din terminalul Linux este comanda „grep”. Numele este un acronim pentru expresia engleză „căutați la nivel global linii care se potrivesc cu expresia regulată și imprimați-le” (căutați peste tot linii care se potrivesc cu expresia regulată și imprimați-le). Comanda „grep” scanează fluxul de intrare linie cu linie, căutând potriviri și iese (filtre) numai acele linii care conțin text care se potrivește cu modelul dat - expresie regulată.

Expresiile regulate sunt un limbaj formal special pentru căutarea și manipularea subșirurilor în text, pe baza utilizării metacaracterelor. Acum aproape toate limbajele de programare moderne au suport încorporat pentru expresiile regulate pentru procesarea textului, dar din punct de vedere istoric, lumea UNIX și, în special, ideile încorporate în comenzile „grep”, „sed”, etc., au contribuit foarte mult. la popularizarea acestei abordări Filosofia „totul este un fișier” » pătrunde complet în UNIX și stăpânirea instrumentelor cu care se lucrează. fișiere text este una dintre abilitățile obligatorii pentru fiecare utilizator Linux.

EŞANTION

GIST | Cea mai simplă căutare toate rândurile care conțin textul „Adams”. Când formatăm acest exemplu și exemplele ulterioare, vom respecta următoarea ordine: parametrii liniei de comandă în partea de sus, fluxurile standard în partea de jos, intrarea stdin în stânga și ieșirea stdout în dreapta.

Comanda „grep” are un număr impresionant de opțiuni pe care le puteți specifica atunci când o rulați. Puteți face o mulțime de lucruri utile cu aceste opțiuni și nici măcar nu trebuie să fiți bine versați în sintaxa expresiilor regulate.

OPȚIUNI

Să începem cu faptul că „grep” nu poate doar să filtreze standard de intrare stdin, ci și să caute prin fișiere. În mod implicit, grep va căuta numai fișierele din directorul curent, dar puteți folosi opțiunea foarte utilă --recursive pentru a-i spune grep să caute recursiv pornind de la un director dat.

GIST | În mod implicit, comanda grep ține seama de majuscule și minuscule. Următorul exemplu arată cum puteți căuta fără a ține cont de caz, de exemplu, „Adams” și „adams” sunt același lucru:

Ignorați majusculele „adams”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 John Adams, 1797-1801

GIST | Căutarea este invers (uneori se spune căutare inversată), adică toate liniile vor fi afișate, cu excepția celor care au o apariție a modelului specificat:

Meci inversat „Adams”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 George Washington, 1789-1797 Thomas Jefferson, 1801-1809

GIST | Opțiunile, desigur, pot și ar trebui să fie combinate între ele. De exemplu, o căutare inversă cu afișarea numerelor de serie ale liniilor cu apariții:

Număr-linie --invert-match „Adams”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 1:George Washington, 1789-1797 3:Thomas Jefferson, 1801-1809

GIST | Colorare. Uneori este convenabil când cuvântul pe care îl căutăm este evidențiat în culoare. Toate acestea sunt deja în „grep”, tot ce rămâne este să includă:

Line-number --color=always "Adams"

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 2:John Adams, 1797-1801

GIST | Dorim să selectăm toate erorile din fișierul jurnal, dar știm că următoarea linie după eroare poate conține informatii utile, atunci este convenabil să scoateți mai multe linii din context. În mod implicit, grep va imprima doar linia în care a fost găsită potrivirea, dar există mai multe opțiuni pentru a face grep print mai mult. Pentru a scoate mai multe linii (în cazul nostru două) după o intrare:

Culoare = întotdeauna -A2 „Adams”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 James Madison, 1809-1817 James Monroe, 1817-1825 John Adams, 1797-1801 Thomas Jefferson, 1801-1819

GIST | La fel pentru ieșirea suplimentară a mai multor linii înainte de intrare:

Culoare = întotdeauna -B2 „James”

George Washington, 1789-1797 John Adams, 1797-1801. Thomas Jefferson, 1801-1809. James Madison. , 1817-1825

GIST | Cu toate acestea, cel mai adesea trebuie să afișați un context simetric, există o notație și mai scurtă pentru aceasta. Să tipărim două rânduri atât deasupra cât și sub intrare:

Culoare = întotdeauna -C2 „James”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 James Madison, 1809-1817 James Monroe, 1817-1825 John Quincy Adams, 1825-1829 Andrew Jackson, 1829-1814 Martin Van-18314 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 James Madison, 1809-1817 James Monroe, 1817-1825 John Quincy Adams, 1825-1829 Andrew Jackson, 1829-1837

GIST | Când căutați qwe, implicit „grep” va afișa și combinații qwe123, 345qwerty și similare. Să găsim doar acele rânduri care dezactivează întregul cuvânt:

Word-regexp --color=întotdeauna „Ioan”

John Fitzgerald Kennedy, 1961-1963 Lyndon Baines Johnson, 1963-1969 John Fitzgerald Kennedy, 1961-1963

GIST | Și, în sfârșit, dacă doriți doar să știți numărul de linii cu potriviri ale unui singur număr, dar să nu afișați nimic altceva:

Count --color=always "Ioan"

John Fitzgerald Kennedy, 1961-1963 Lyndon Baines Johnson, 1963-1969 Richard Milhous Nixon, 1969-1974 2

Este de remarcat faptul că majoritatea opțiunilor au o contrapartidă, de exemplu --ignore-case poate fi redusă la forma mai scurtă -i etc.

EXPRESII REGULARE DE BAZĂ

Toate expresiile regulate constau din două tipuri de caractere: standard caractere text, numit literali, iar caracterele speciale numite metacaracterele. În exemplele anterioare, căutarea a fost efectuată folosind literale (potrivirea exactă a literelor), dar ceea ce urmează va fi mult mai interesant. Bun venit în lumea expresiilor regulate!

Semnele caret ^ și dolar $ au semnificații speciale într-o expresie obișnuită. Ele sunt numite „ancore”. Ancorele sunt caractere speciale care indică locația într-un șir a potrivirii dorite. Când căutarea ajunge la o ancoră, verifică dacă există o potrivire și, dacă da, continuă să urmeze modelul. fără a adăuga nimic la rezultat.

GIST | Ancora caret este folosită pentru a indica faptul că expresia regulată trebuie testată de la începutul liniei:

Culoare=întotdeauna „^J”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 John Adams, 1797-1801

GIST | În mod similar, ancora dolar ar trebui să fie folosită la sfârșitul modelului pentru a indica faptul că potrivirea este validă numai dacă șirul de caractere căutat se află la sfârșitul șirului de text și nu altfel:

Culoare=întotdeauna „9$”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 Thomas Jefferson, 1801-1809

GIST | Orice personaj. Caracterul punct este folosit în expresiile regulate pentru a indica faptul că absolut orice caracter poate apărea în locația specificată:

Culoare=întotdeauna „0.$”

GIST | Ecranarea. Dacă trebuie să găsiți exact simbolul punctului, atunci evadarea va ajuta. Un caracter de escape (de obicei o bară oblică inversă) care precede un caracter, cum ar fi un punct, transformă metacaracterul într-un literal:

Culoare=întotdeauna „\.”

George Washington. 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 George Washington. 1789-1797

GIST | Clasele de caractere. Expresiile regulate pot folosi intervale și clase de caractere. Pentru a face acest lucru, se folosesc paranteze pătrate atunci când se creează un șablon. Prin plasarea unui grup de caractere (inclusiv caractere care altfel ar fi interpretate ca metacaractere) între paranteze drepte, puteți indica că oricare dintre caracterele dintre paranteze poate apărea în acea poziție:

Culoare = întotdeauna „0”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 John Adams, 1797-1801 Thomas Jefferson, 1801-1809

GIST | Gamă. Acestea sunt două caractere separate printr-o cratimă, de exemplu 0-9 (cifre zecimale) sau 0-9a-fA-F (cifre hexazecimale):

Culoare = întotdeauna ""

George Washington, ??? John Adams, 1797-1801 Thomas Jefferson, 1801-1809 John Adams, 1797-1801 Thomas Jefferson, 1801-1809

GIST | Negare. Dacă primul caracter al expresiei dintre paranteze pătrate este un accent, atunci caracterele rămase sunt luate ca un set de caractere care nu ar trebui să fie prezente la poziția dată a expresiei regulate:

Culoare=întotdeauna „[^7]$”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 John Adams, 1797-1801 Thomas Jefferson, 1801-1809

GIST | Clasele de caractere POSIX. Există un anumit set de clase de caractere pre-preparate pe care le puteți folosi în expresiile regulate. Există aproximativ o duzină de ele, doar căutați rapid manualul pentru a înțelege scopul fiecăruia. De exemplu, să filtram numai cifre hexazecimale:

Culoare=întotdeauna „^[[:xdigit:]]*$”

4.2 42 42abc 42 42abc

GIST | Repetați (de 0 sau de mai multe ori). Unul dintre metacaracterele cel mai frecvent utilizate este simbolul asterisc, care înseamnă „repetă caracterul sau expresia anterioară de zero sau de mai multe ori”:

Culoare=întotdeauna „^*$”

George Washington, ??? John Adams, 1797-1801 Thomas Jefferson, 1801-1809 George Washington, ???

Există expresii regulate de bază BRE (expresii regulate de bază) și expresii regulate extinse ERE (expresii regulate extinse). Următoarele metacaractere sunt recunoscute în BRE: ^$. * și toate celelalte caractere sunt tratate ca literale. Au fost adăugate următoarele metacaractere la ERE () ( )? + | și funcții conexe. Ei bine, pentru a deruta complet pe toată lumea, au venit cu chestia asta în „grep” - caracterele () ( ) din BRE sunt tratate ca metacaractere dacă sunt scăpate cu o bară oblică inversă, în timp ce în ERE, plasând o bară oblică inversă în fața orice metacaractere duce la faptul că sunt tratate ca literali.

EXPRESII REGULARE AVANSATE

GIST | Disjuncție. La fel cum parantezele drepte definesc diferit opțiuni posibile se potrivește cu un singur caracter, disjuncția vă permite să specificați potriviri alternative pentru șiruri de caractere sau expresii. Simbolul barei verticale este folosit pentru a indica disjuncția:

Extended-regexp --color=always „George|John”

George Washington, 1789-1797 John Adams, 1797-1801 Thomas Jefferson, 1801-1809 George Washington, 1789-1797 John Adams, 1797-1801

GIST | Potriviți zero sau o singură dată. În expresiile regulate extinse, există câteva metacaractere suplimentare care indică cât de des se repetă un caracter sau o expresie (similar cu modul în care metacaracterul asterisc indică potriviri de 0 sau mai multe ori). Un astfel de metacaracter este semnul întrebării, ceea ce face ca caracterul sau expresia anterioară să fie în esență opțională:

Extended-regexp --color=always „^(Andrew)?John”

John Adams, 1797-1801 Andrew Johnson, 1865-1869 Lyndon Baines Johnson, 1963-1969 John Adams, 1797-1801 Andrew Johnson, 1865-1869

GIST | Potriviți una sau mai multe ori. În acest scop, este furnizat un metacaracter sub forma unui semn plus. Funcționează aproape ca simbolul asterisc, cu excepția faptului că expresia trebuie să se potrivească cel puțin o dată:

Extended-regexp --color=always „^[[:alpha:] ]+$”

John Adams Andrew Johnson, 1865-1869 Lyndon Baines Johnson, 1963-1969 John Adams

GIST | Potriviți numărul specificat de ori. Puteți folosi bretele pentru aceasta. Aceste metacaractere sunt folosite pentru a specifica numărul exact, intervalul și limita superioară și inferioară a numărului de potriviri ale unei expresii:

Extended-regexp --color=întotdeauna „(1,3)\.(1,3)\.(1,3)\.(1,3)”

42 127.0.0.1 127.0.0.1

Comanda grep este atât de utilă, bogată în funcții și ușor de utilizat încât, odată ce o cunoașteți, nu vă puteți imagina că lucrați fără ea.

Expresia regulată- un model de text format dintr-o combinație de litere, cifre și caractere speciale cunoscute sub numele de metacaractere. O rudă apropiată a expresiilor regulate sunt expresiile wildcard, adesea folosite în gestionarea fișierelor. Expresiile regulate sunt folosite în principal pentru compararea textului și căutarea. Folosit pe scară largă pentru analiza sintaxei.

Utilizatorii UNIX sunt familiarizați cu expresiile regulate din grep, sed, awk (sau gawk) și ed. Folosind aceste programe sau analogii lor, puteți încerca și verifica exemplele de mai jos. Editori de text programe precum (X)Emacs și vi folosesc, de asemenea, expresiile regulate. Poate cea mai cunoscută și mai răspândită utilizare a expresiilor regulate are loc în limbajul Perl. Este dificil pentru dezvoltatorii de software și administratorii de sistem să se descurce fără cunoașterea expresiilor regulate.

Metacaracterele

Deci, șirurile pot consta din litere, cifre și metacaractere. Metacaracterele sunt:

\ | () { } ^ $ * + ? . < >

Metacaracterele pot juca următoarele roluri într-o expresie regulată:

    cuantificator

    declaraţie;

    semn de grup;

    alternativă;

    semnul secvenței

Cuantificatori

Metacaracterul * (asterisc) înlocuiește 0 sau mai multe caractere. Metacaracterul + (plus) înlocuiește 1 sau mai multe caractere. Metacaracter. (punct) înlocuiește exact 1 caracter arbitrar. Metacaracter? (semnul de întrebare) înlocuiește 0 sau 1 caracter. Diferența în utilizarea * și + este de așa natură încât o interogare pentru șirul c* va returna orice șiruri, inclusiv cele goale, în timp ce o interogare cu c+ va returna doar șiruri care conțin caracterul c.

Liniile goale respectă următoarele convenții: o linie goală conține una și o singură linie goală; într-un șir nevid, liniile goale sunt conținute înaintea fiecărui caracter și, de asemenea, la sfârșitul rândului.

Expresiile regulate folosesc și construcția (n,m), ceea ce înseamnă că caracterul care precede construcția apare de n la m ori pe linie. Omitând numărul m înțelegem infinit. Aceste. cazuri speciale de construcție sunt următoarele înregistrări: (0,) , (1,) și (0,1) . Primul se potrivește cu *, al doilea se potrivește cu metacaracterul +, iar al treilea se potrivește? . Aceste egalități pot fi obținute cu ușurință din definirea cuantificatorilor corespunzători. În plus, construcția (n) înseamnă că simbolul apare exact de n ori.

În legătură cu utilizarea unor semne de punctuație și simboluri matematice ca metacaractere, a fost introdus un metacaracter suplimentar \ (backslash), care, atunci când este scris înaintea unui metacaracter, îl transformă pe acesta din urmă într-un caracter obișnuit. Aceste. ? este un cuantificator și \? - semnul întrebării.

Grupuri

Cuantificatorii descriși mai sus, așa cum sa menționat deja, acționează pe simbolul cel mai apropiat de ei din stânga (ultimul precedent). Dar această limitare poate fi ocolită de grupurile care folosesc metacaractere (și) în denumirile lor. Aceste simboluri izolează o subexpresie dintr-o expresie, care este combinată într-un grup, căruia i se aplică apoi cuantificatorul.

Exemplu:

înseamnă (sau înlocuiește)

Ho ho ho ho ho ho hohoho

Sunt posibile imbricarea subexpresiilor, de ex. Subexpresiile de lungime mai scurtă pot fi extrase dintr-o subexpresie.

Alternative

Format folosind metasimbolul | (bară verticală) care denotă un „sau” logic.

Exemplu: expresie regulată cows(a|s|e|y|oh|oh)? specifică toate inflexiunile posibile ale cuvântului „vacă” la singular după caz.

Declarații

Se identifică metacaracterele care denotă obiecte speciale - linii de lungime zero care servesc la determinarea locației textului care le precede sau le urmează. Astfel de obiecte se numesc aserțiuni. Următoarele afirmații există în expresiile regulate:

^ începutul rândului $ sfârşitul rândului< начало слова >sfârşitul cuvântului

Exemplu: Expresia regulată $The se potrivește cu un șir care începe cu The .

Notă: caracterele obișnuite pot fi tratate ca instrucțiuni cu lungime diferită de zero.

Secvențe

O construcție specială închisă în metacaractere [ și ] (paranteze dreptunghiulare) vă permite să enumerați variante de caractere care pot apărea într-o expresie regulată într-un loc dat și se numește secvență. În paranteze dreptunghiulare, toate metacaracterele sunt tratate ca caractere simple, iar simbolurile - (minus) și ^ capătă semnificații noi: primul vă permite să specificați o secvență continuă de caractere între două caractere specificate, iar al doilea dă un „nu” logic. ” (negație). Cel mai ușor este să luați în considerare următoarele exemple:

oricare dintre literele latine mici:

Caracter alfanumeric latin (de la a la z, de la A la Z și de la 0 la 9):

caracter alfanumeric non-latin:

[^a-zA-Z0-9]

orice cuvânt (fără cratime, simboluri matematice și numere):

<+>

Pentru concizie și simplitate, sunt introduse următoarele abrevieri:

\d cifră (adică corespunde expresiei);

\D nu este o cifră (adică [^0-9]);

\w cuvânt latin (alfanumeric);

    \W este o secvență de caractere fără spații care nu este un cuvânt alfanumeric latin ([^a-zA-Z0-9]);

    \s spațiu gol [ \t\n\r\f] , adică. spații, file etc.

    \S interval nevid ([^ \t\n\r\f]).

Relația cu metacaracterele

Probabil că fiecare utilizator este familiarizat cu metacaracterele. Un exemplu de expresie wildcard este *.jpg, care reprezintă toate fișierele cu extensia jpg. Cum diferă expresiile regulate de metacaracterele? Diferențele pot fi rezumate în trei reguli pentru conversia unei expresii arbitrare cu metacaractere într-o expresie regulată:

Înlocuiește * cu.*

Înlocui? pe. [email protected]

+(\.+)*@+(\.+)+

Înlocuiți toate caracterele care se potrivesc cu metacaracterele cu variantele lor cu bară oblică inversă. "

Într-adevăr, într-o expresie regulată, intrarea * este inutilă și produce un șir gol, deoarece înseamnă că linia goală se repetă de câte ori se dorește. Dar * (repetați un simbol arbitrar de câte ori doriți, inclusiv 0) coincide exact ca semnificație cu simbolul * din setul de wildcards.<+(\.+)*@+(\.+)+\>

O expresie regulată care se potrivește cu *.jpg ar arăta astfel: .*\.jpg . Și, de exemplu, succesiunea de caractere metalice ez*.pp corespunde la două expresii regulate echivalente - ez.*\.pp și ez.*\.(cpp|hpp) .

+://

Exemple de expresii regulate

Format de e-mail<"][^>E-mail în formatul „Ivan Ivanov

("?+"?[ \t]*)+\

Verificarea protocolului web în adresa URL (http://, ftp:// sau https://)

-?+\.+ - număr în virgulă mobilă

0x+ este un număr din sistemul numeric hexazecimal.

Și iată, de exemplu, un program pentru a căuta cuvântul vaca:

grep -E „vacă|vache” * >/ dev/ null && echo „Găsit o vaca”

Aici opțiunea -E este folosită pentru a activa suportul pentru sintaxa extinsă a expresiilor regulate.

Textul se bazează pe un articol al lui Jan Borsodi din fișierul HOWTO-regexps.htm