Reguljära uttryck i bash. Bash reguljära uttryck: skapande guide, applikation, exempel. Punkt för att indikera ett tecken

Reguljära uttryck är ett mycket kraftfullt verktyg för att söka text efter mönster, bearbeta och modifiera strängar, som kan användas för att lösa många problem. Här är de viktigaste:

  • Kontroll av textinmatning;
  • Sök och ersätt text i en fil;
  • Batchbyte av filer;
  • Interaktion med tjänster som Apache;
  • Kontrollera att en sträng matchar ett mönster.

Detta är inte en komplett lista; reguljära uttryck låter dig göra mycket mer. Men för nya användare kan de verka för komplicerade, eftersom de använder ett speciellt språk för att skapa dem. Men med tanke på de möjligheter som tillhandahålls bör varje systemadministratör känna till och kunna använda Linux reguljära uttryck.

I den här artikeln kommer vi att titta på bash reguljära uttryck för nybörjare så att du kan förstå alla funktioner i det här verktyget.

Det finns två typer av tecken som kan användas i reguljära uttryck:

  • vanliga bokstäver;
  • metakaraktärer.

Vanliga tecken är bokstäverna, siffrorna och skiljetecken som utgör en sträng. Alla texter är uppbyggda av bokstäver och du kan använda dem i reguljära uttryck för att hitta önskad position i texten.

Metakaraktärer är något annat de är det som ger reguljära uttryck sin kraft. Med metatecken kan du göra mycket mer än att bara söka efter ett enda tecken. Du kan söka efter symbolkombinationer, använda ett dynamiskt antal symboler och välja intervall. Alla specialtecken kan delas in i två typer: ersättningstecken, som ersätter vanliga tecken, eller operatorer, som anger hur många gånger ett tecken kan upprepas. Syntaxen för reguljära uttryck skulle se ut så här:

vanlig_karaktär special character_operator

special_replacement_character special character_operator

  • — Alfabetiska specialtecken börjar med ett omvänt snedstreck, och det används också om du behöver använda ett specialtecken i form av ett skiljetecken;
  • ^ — anger början av raden;
  • $ — anger slutet av raden;
  • * — indikerar att det föregående tecknet kan upprepas 0 eller fler gånger;
  • + — indikerar att det föregående tecknet ska upprepas en eller flera gånger;
  • ? — det föregående tecknet kan förekomma noll eller en gång;
  • (n)— anger hur många gånger (n) det föregående tecknet ska upprepas;
  • (N,n)— det föregående tecknet kan upprepas från N till n gånger;
  • . — alla tecken utom radmatning;
  • — Alla tecken som anges inom parentes.
  • x|y— symbol x eller symbol y;
  • [^az]- alla tecken utom de som anges inom parentes;
  • — alla tecken från det angivna intervallet.
  • [^a-z]— Alla tecken som inte ingår i intervallet.
  • b— betecknar en ordgräns med ett mellanslag;
  • B— betyder att tecknet måste finnas i ett ord, till exempel kommer ux att matcha uxb eller smoking, men kommer inte att matcha Linux;
  • d— betyder att symbolen är en siffra;
  • D— icke-numeriskt tecken.
  • n— radmatningskaraktär;
  • s- ett av mellanslagstecknen, mellanslag, tab, och så vidare;
  • S— vilket tecken som helst utom mellanslag.
  • t— tab-tecken;
  • v— vertikalt tabbtecken;
  • w- alla alfabetiska tecken, inklusive understreck;
  • W- alla alfabetiska tecken, utom understreck;
  • uXXX— Unicdoe-symbol.

Det är viktigt att notera att du måste använda ett snedstreck före alfabetiska specialtecken för att indikera att ett specialtecken kommer härnäst. Det omvända är också sant, om du vill använda ett specialtecken som används utan snedstreck som ett vanligt tecken, då måste du lägga till ett snedstreck.

Till exempel vill du hitta raden 1+ 2=3 i texten. Om du använder denna sträng som ett reguljärt uttryck hittar du ingenting, eftersom systemet tolkar plustecknet som ett specialtecken som indikerar att föregående enhet ska upprepas en eller flera gånger. Så det måste escapes: 1 + 2 = 3. Utan escape, skulle vårt reguljära uttryck bara matcha strängen 11=3 eller 111=3 och så vidare. Det finns ingen anledning att sätta en linje framför lika, eftersom det inte är en speciell karaktär.

Exempel på användning av reguljära uttryck

Nu när vi har täckt grunderna och du vet hur allt fungerar, återstår bara att konsolidera kunskapen du har fått om linux grep reguljära uttryck i praktiken. Två mycket användbara specialtecken är ^ och $, som indikerar början och slutet av en rad. Vi vill till exempel få alla användare registrerade i vårt system vars namn börjar med s. Då kan du använda ett reguljärt uttryck "^s". Du kan använda kommandot egrep:

egrep "^s" /etc/passwd

Om vi ​​vill välja rader utifrån det sista tecknet i raden kan vi använda $ för detta. Låt oss till exempel välja alla systemanvändare, utan ett skal, poster om sådana användare slutar på false:

egrep "false$" /etc/passwd

För att visa användarnamn som börjar med s eller d, använd detta uttryck:

egrep "^" /etc/passwd

Samma resultat kan erhållas genom att använda symbolen "|". Det första alternativet är mer lämpligt för intervall, och det andra används oftare för vanliga eller/eller:

egrep "^" /etc/passwd

Låt oss nu välja alla användare vars namn inte är tre tecken långt. Användarnamnet slutar med ett kolon. Vi kan säga att det kan innehålla alla alfabetiska tecken, som måste upprepas tre gånger, före kolon:

egrep "^w(3):" /etc/passwd

Slutsatser

I den här artikeln täckte vi Linux reguljära uttryck, men det var bara grunderna. Om du gräver lite djupare kommer du att upptäcka att du kan göra mycket mer intressanta saker med det här verktyget. Att ta sig tid att bemästra reguljära uttryck kommer definitivt att vara värt det.

Som avslutning, en föreläsning från Yandex om reguljära uttryck:

För att fullständigt bearbeta texter i bash-skript med sed och awk behöver du bara förstå reguljära uttryck. Implementeringar av detta mest användbara verktyg kan hittas bokstavligen överallt, och även om alla reguljära uttryck är strukturerade på ett liknande sätt och bygger på samma idéer, har det vissa funktioner att arbeta med dem i olika miljöer. Här kommer vi att prata om reguljära uttryck som är lämpliga för användning i Linux kommandoradsskript.

Detta material är tänkt som en introduktion till reguljära uttryck, avsett för dem som kanske är helt omedvetna om vad de är. Så låt oss börja från början.

Vad är reguljära uttryck

Många människor, när de först ser vanliga uttryck, tror genast att de tittar på ett meningslöst virrvarr av karaktärer. Men detta är naturligtvis långt ifrån fallet. Ta en titt på detta regex till exempel


Enligt vår mening kommer även en absolut nybörjare omedelbart att förstå hur det fungerar och varför det behövs :) Om du inte riktigt förstår det, läs bara vidare så faller allt på plats.
Ett reguljärt uttryck är ett mönster som program som sed eller awk använder för att filtrera text. Mallar använder vanliga ASCII-tecken som representerar sig själva, och så kallade metatecken som spelar en speciell roll, t.ex. tillåter referenser till vissa grupper av tecken.

Typer av reguljära uttryck

Implementeringar av reguljära uttryck i olika miljöer, till exempel i programmeringsspråk som Java, Perl och Python, och i Linux-verktyg som sed, awk och grep, har vissa funktioner. Dessa funktioner är beroende av så kallade reguljära uttrycksmotorer, som tolkar mönster.
Linux har två reguljära uttrycksmotorer:
  • En motor som stöder standarden POSIX Basic Regular Expression (BRE).
  • En motor som stöder standarden POSIX Extended Regular Expression (ERE).
De flesta Linux-verktyg överensstämmer med åtminstone POSIX BRE-standarden, men vissa verktyg (inklusive sed) förstår bara en delmängd av BRE-standarden. En av anledningarna till denna begränsning är önskan att göra sådana verktyg så snabbt som möjligt vid textbehandling.

POSIX ERE-standarden implementeras ofta i programmeringsspråk. Det låter dig använda ett stort antal verktyg när du utvecklar reguljära uttryck. Det kan till exempel vara speciella teckensekvenser för ofta använda mönster, som att söka efter enskilda ord eller uppsättningar av siffror i text. Awk stöder ERE-standarden.

Det finns många sätt att utveckla reguljära uttryck, beroende både på programmerarens åsikt och på funktionerna i motorn som de är skapade för. Det är inte lätt att skriva universella reguljära uttryck som vilken motor som helst kan förstå. Därför kommer vi att fokusera på de vanligaste reguljära uttrycken och titta på funktionerna i deras implementering för sed och awk.

POSIX BRE reguljära uttryck

Det kanske enklaste BRE-mönstret är ett reguljärt uttryck för att söka efter den exakta förekomsten av en sekvens av tecken i text. Så här ser det ut att söka efter en sträng i sed och awk:

$ echo "Detta är ett test" | sed -n "/test/p" $ echo "Detta är ett test" | awk "/test/(print $0)"

Hitta text efter mönster i sed


Hitta text efter mönster i awk

Du kanske märker att sökningen efter ett givet mönster utförs utan att ta hänsyn till den exakta platsen för texten i raden. Dessutom spelar antalet händelser ingen roll. Efter att det reguljära uttrycket hittar den angivna texten var som helst i strängen anses strängen vara lämplig och skickas vidare för vidare bearbetning.

När du arbetar med reguljära uttryck måste du ta hänsyn till att de är skiftlägeskänsliga:

$ echo "Detta är ett test" | awk "/Test/(print $0)" $ echo "Detta är ett test" | awk "/test/(print $0)"

Reguljära uttryck är skiftlägeskänsliga

Det första reguljära uttrycket hittade inga matchningar eftersom ordet "test", som börjar med en stor bokstav, inte förekommer i texten. Den andra, konfigurerad för att söka efter ett ord skrivet med versaler, hittade en lämplig rad i strömmen.

I reguljära uttryck kan du inte bara använda bokstäver utan även mellanslag och siffror:

$ echo "Detta är ett test 2 igen" | awk "/test 2/(print $0)"

Hitta ett stycke text som innehåller mellanslag och siffror

Mellanslag behandlas som vanliga tecken av motorn för reguljära uttryck.

Specialsymboler

När du använder olika tecken i reguljära uttryck finns det några saker att tänka på. Det finns alltså några specialtecken, eller metatecken, vars användning i en mall kräver ett speciellt tillvägagångssätt. Här är de:

.*^${}\+?|()
Om en av dem behövs i mallen, kommer den att behöva escapes med ett snedstreck (omvänt snedstreck) - \ .

Om du till exempel behöver hitta ett dollartecken i texten måste du inkludera det i mallen, föregås av ett escape-tecken. Låt oss säga att det finns en fil myfile med följande text:

Det finns 10$ på min ficka
Dollartecknet kan upptäckas med detta mönster:

$awk "/\$/(skriv ut $0)" min fil

Använda ett specialtecken i ett mönster

Dessutom är omvänt snedstreck också ett specialtecken, så om du behöver använda det i ett mönster kommer det också att behöva escapes. Det ser ut som två snedstreck som följer efter varandra:

$ echo "\ är ett specialtecken" | awk "/\\/(skriv ut $0)"

Undviker ett snedstreck

Även om snedstrecket inte ingår i listan över specialtecken ovan, kommer ett försök att använda det i ett reguljärt uttryck skrivet för sed eller awk att resultera i ett fel:

$ echo "3/2" | awk "///(print $0)"

Felaktig användning av snedstreck i ett mönster

Om det behövs måste det också undvikas:

$ echo "3/2" | awk "/\//(skriv ut $0)"

Undviker ett snedstreck framåt

Ankare symboler

Det finns två specialtecken för att länka ett mönster till början eller slutet av en textsträng. Captecknet - ^ låter dig beskriva sekvenser av tecken som finns i början av textrader. Om mönstret du letar efter finns någon annanstans i strängen, kommer det reguljära uttrycket inte att svara på det. Användningen av denna symbol ser ut så här:

$ echo "välkommen till likegeeks hemsida" | awk "/^likegeeks/(skriv ut $0)" $ echo "likegeeks hemsida" | awk "/^likegeeks/(skriv ut $0)"

Hitta ett mönster i början av en sträng

Tecknet ^ är utformat för att söka efter ett mönster i början av en rad, medan fallet med tecken också tas med i beräkningen. Låt oss se hur detta påverkar behandlingen av en textfil:

$awk "/^this/(skriv ut $0)" min fil


Hitta ett mönster i början av en rad i text från en fil

När du använder sed, om du placerar en keps någonstans inuti mönstret, kommer den att behandlas som vilken annan vanlig karaktär som helst:

$ echo "Detta ^ är ett test" | sed -n "/s ^/p"

Keps inte i början av mönstret i sed

I awk, när du använder samma mall, måste detta tecken escapes:

$ echo "Detta ^ är ett test" | awk "/s\^/(skriv ut $0)"

Täck inte i början av mallen i awk

Vi har listat ut sökningen efter textfragment som finns i början av en rad. Vad händer om du behöver hitta något i slutet av en rad?

Dollartecknet - $, som är ankartecknet för slutet av raden, hjälper oss med detta:

$ echo "Detta är ett test" | awk "/test$/(print $0)"

Hitta text i slutet av en rad

Du kan använda båda ankarsymbolerna i samma mall. Låt oss bearbeta filen myfile, vars innehåll visas i figuren nedan, med hjälp av följande reguljära uttryck:

$ awk "/^detta är en test$/(skriv ut $0)" min fil


Ett mönster som använder specialtecken för att starta och avsluta en rad

Som du kan se, svarade mallen endast på en rad som helt motsvarade den givna sekvensen av tecken och deras plats.

Så här filtrerar du bort tomma rader med ankartecken:

$awk "!/^$/(skriv ut $0)" min fil
I den här mallen använde jag en negationssymbol, ett utropstecken - ! . Genom att använda det här mönstret söker man efter linjer som inte innehåller någonting mellan början och slutet av raden, och tack vare utropstecken skrivs endast linjer som inte matchar detta mönster ut.

Punktsymbol

Perioden används för att matcha ett enskilt tecken utom nyradstecknet. Låt oss skicka filen myfile till detta reguljära uttryck, vars innehåll anges nedan:

$awk "/.st/(skriv ut $0)" min fil


Använder en punkt i reguljära uttryck

Som kan ses av utdata, motsvarar endast de två första raderna från filen mönstret, eftersom de innehåller sekvensen av tecken "st" föregås av ett annat tecken, medan den tredje raden inte innehåller en lämplig sekvens, och fjärde har det, men är med i början av raden.

Karaktärsklasser

En prick matchar varje enskilt tecken, men vad händer om du vill vara mer flexibel när det gäller att begränsa uppsättningen tecken du letar efter? I den här situationen kan du använda karaktärsklasser.

Tack vare detta tillvägagångssätt kan du organisera en sökning efter vilken karaktär som helst från en given uppsättning. För att beskriva en teckenklass används hakparenteser:

$awk "/th/(skriv ut $0)" min fil


Beskrivning av en teckenklass i ett reguljärt uttryck

Här letar vi efter en sekvens av "te" tecken som föregås av ett "o"-tecken eller ett "i"-tecken.

Klasser är praktiska när du söker efter ord som kan börja med antingen en stor eller liten bokstav:

$ echo "det här är ett test" | awk "/hans är ett test/(skriv ut $0)" $ echo "Detta är ett test" | awk "/hans är ett test/(skriv ut $0)"

Sök efter ord som kan börja med en liten eller stor bokstav

Karaktärsklasser är inte begränsade till bokstäver. Andra symboler kan användas här. Det är omöjligt att säga i förväg i vilken situation klasser kommer att behövas - allt beror på att problemet löses.

Negation av karaktärsklasser

Teckenklasser kan också användas för att lösa det omvända problemet som beskrivs ovan. Istället för att söka efter symboler som ingår i en klass kan du nämligen organisera en sökning efter allt som inte ingår i klassen. För att uppnå detta reguljära uttrycksbeteende måste du placera ett ^-tecken framför listan med klasstecken. Det ser ut så här:

$ awk "/[^oi]th/(print $0)" min fil


Hitta karaktärer som inte ingår i en klass

I det här fallet kommer sekvenser av "te" tecken att hittas som föregås av varken "o" eller "i".

Karaktärsintervall

I teckenklasser kan du beskriva teckenintervall med hjälp av bindestreck:

$awk "/st/(skriv ut $0)" min fil


Beskrivning av ett antal tecken i en teckenklass

I det här exemplet svarar det reguljära uttrycket på sekvensen av tecken "st" som föregås av ett tecken som är placerat, i alfabetisk ordning, mellan tecknen "e" och "p".

Områden kan också skapas från siffror:

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

Reguljärt uttryck för att hitta valfria tre tal

En teckenklass kan inkludera flera intervall:

$awk "/st/(skriv ut $0)" min fil


En teckenklass som består av flera intervall

Detta reguljära uttryck hittar alla sekvenser av "st" som föregås av tecken från intervallen a-f och m-z .

Specialkaraktärsklasser

BRE har speciella teckenklasser som du kan använda när du skriver reguljära uttryck:
  • [[:alpha:]] - matchar alla alfabetiska tecken, skrivna med stora eller små bokstäver.
  • [[:alnum:]] - matchar alla alfanumeriska tecken, nämligen tecken i intervallen 0-9 , A-Z , a-z .
  • [[:blank:]] - matchar ett mellanslag och ett tabbtecken.
  • [[:siffra:]] - valfritt tecken från 0 till 9.
  • [[:upper:]] - stora bokstäver - A-Z .
  • [[:lower:]] - små bokstäver - a-z .
  • [[:print:]] - matchar alla utskrivbara tecken.
  • [[:punct:]] - matchar skiljetecken.
  • [[:mellanslag:]] - blanksteg, i synnerhet - mellanslag, tab, tecken NL, FF, VT, CR.
Du kan använda specialklasser i mallar så här:

$ echo "abc" | awk "/[[:alpha:]]/(print $0)" $ echo "abc" | awk "/[[:digit:]]/(print $0)" $ echo "abc123" | awk "/[[:siffra:]]/(skriv ut $0)"


Specialteckenklasser i reguljära uttryck

Stjärnsymbol

Om du placerar en asterisk efter ett tecken i ett mönster kommer det att innebära att det reguljära uttrycket fungerar om tecknet förekommer i strängen hur många gånger som helst - inklusive situationen när tecknet saknas i strängen.

$ echo "test" | awk "/tes*t/(skriv ut $0)" $ echo "tessst" | awk "/tes*t/(skriv ut $0)"


Använda tecknet * i reguljära uttryck

Detta jokertecken används vanligtvis för ord som ständigt stavas fel, eller för ord som har olika stavningar:

$ echo "Jag gillar grön färg" | awk "/colou*r/(print $0)" $ echo "Jag gillar grön färg " | awk "/colou*r/(print $0)"

Hitta ett ord med olika stavningar

I det här exemplet svarar samma reguljära uttryck på både ordet "färg" och ordet "färg". Detta beror på det faktum att tecknet "u", följt av en asterisk, antingen kan vara frånvarande eller visas flera gånger i rad.

En annan användbar funktion som kommer från asterisksymbolen är att kombinera den med en prick. Denna kombination låter det reguljära uttrycket svara på valfritt antal tecken:

$ awk "/this.*test/(print $0)" min fil


En mall som svarar på valfritt antal tecken

I det här fallet spelar det ingen roll hur många och vilka tecken som finns mellan orden "detta" och "testa".

Asterisken kan också användas med teckenklasser:

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


Använda en asterisk med teckenklasser

I alla tre exemplen fungerar det reguljära uttrycket eftersom asterisken efter teckenklassen betyder att om valfritt antal "a" eller "e" tecken hittas, eller om inga hittas, kommer strängen att matcha det givna mönstret.

POSIX ERE reguljära uttryck

POSIX ERE-mallarna som vissa Linux-verktyg stöder kan innehålla ytterligare tecken. Som redan nämnts stöder awk denna standard, men sed gör det inte.

Här kommer vi att titta på de mest använda symbolerna i ERE-mönster, som kommer att vara användbara för dig när du skapar dina egna reguljära uttryck.

▍Frågetecken

Ett frågetecken anger att det föregående tecknet kan förekomma en gång eller inte alls i texten. Den här karaktären är en av upprepningsmetakaraktärerna. Här är några exempel:

$ echo "tet" | awk "/tes?t/(print $0)" $ echo "test" | awk "/tes?t/(print $0)" $ echo "testst" | awk "/tes?t/(print $0)"


Frågetecken i reguljära uttryck

Som du kan se, i det tredje fallet visas bokstaven "s" två gånger, så det reguljära uttrycket svarar inte på ordet "testst".

Frågetecknet kan också användas med teckenklasser:

$ echo "tst" | awk "/t?st/(print $0)" $ echo "test" | awk "/t?st/(print $0)" $ echo "tast" | awk "/t?st/(print $0)" $ echo "taest" | awk "/t?st/(print $0)" $ echo "test" | awk "/t?st/(print $0)"


Frågetecken och karaktärsklasser

Om det inte finns några tecken från klassen på raden, eller ett av dem förekommer en gång, fungerar det reguljära uttrycket, men så fort två tecken dyker upp i ordet hittar systemet inte längre en matchning för mönstret i texten.

▍Plussymbol

Plustecknet i mönstret anger att det reguljära uttrycket kommer att matcha det det letar efter om det föregående tecknet förekommer en eller flera gånger i texten. Denna konstruktion kommer dock inte att reagera på frånvaron av en symbol:

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


Plussymbolen i reguljära uttryck

I det här exemplet, om det inte finns något "e"-tecken i ordet, hittar inte motorn för reguljära uttryck matchningar med mönstret i texten. Plussymbolen fungerar också med teckenklasser - på så sätt liknar den asterisken och frågetecknet:

$ echo "tst" | awk "/t+st/(print $0)" $ echo "test" | awk "/t+st/(print $0)" $ echo "teast" | awk "/t+st/(print $0)" $ echo "teeast" | awk "/t+st/(print $0)"


Plus tecken och tecken klasser

I det här fallet, om raden innehåller något tecken från klassen, kommer texten att anses matcha mönstret.

▍Kulliga hängslen

Lockiga hängslen, som kan användas i ERE-mönster, liknar symbolerna som diskuterats ovan, men de låter dig mer exakt specificera det antal förekomster som krävs av symbolen som föregår dem. Du kan ange en begränsning i två format:
  • n - ett nummer som anger det exakta antalet sökta förekomster
  • n, m är två tal som tolkas enligt följande: "minst n gånger, men inte mer än m."
Här är exempel på det första alternativet:

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

Lockiga hängslen i mönster, söker efter det exakta antalet förekomster

I äldre versioner av awk var du tvungen att använda kommandoradsalternativet --re-interval för att få programmet att känna igen intervall i reguljära uttryck, men i nyare versioner är detta inte nödvändigt.

$ 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/(print $0)"


Avstånd specificerat i lockiga hängslen

I det här exemplet måste tecknet "e" visas 1 eller 2 gånger på raden, då kommer det reguljära uttrycket att svara på texten.

Lockiga hängslen kan också användas med karaktärsklasser. De principer du redan känner till gäller här:

$ echo "tst" | awk "/t(1,2)st/(print $0)" $ echo "test" | awk "/t(1,2)st/(print $0)" $ echo "test" | awk "/t(1,2)st/(print $0)" $ echo "teeast" | awk "/t(1,2)st/(print $0)"


Lockiga hängslen och karaktärsklasser

Mallen kommer att reagera på texten om den innehåller tecknet "a" eller tecknet "e" en eller två gånger.

▍Logisk "eller"-symbol

Symbol | - en vertikal stapel betyder ett logiskt "eller" i reguljära uttryck. Vid bearbetning av ett reguljärt uttryck som innehåller flera fragment åtskilda av ett sådant tecken, kommer motorn att anse den analyserade texten som lämplig om den matchar något av fragmenten. Här är ett exempel:

$ echo "Detta är ett test" | awk "/test|exam/(print $0)" $ echo "Detta är en tentamen" | awk "/test|exam/(print $0)" $ echo "Detta är något annat" | awk "/test|exam/(print $0)"


Logiskt "eller" i reguljära uttryck

I det här exemplet är det reguljära uttrycket konfigurerat för att söka i texten efter orden "test" eller "examen". Observera att mellan mallfragmenten och symbolen som skiljer dem | det ska inte finnas några mellanslag.

Reguljära uttrycksfragment kan grupperas med hjälp av parenteser. Om du grupperar en viss teckensekvens kommer den att uppfattas av systemet som en vanlig karaktär. Det vill säga att till exempel upprepningsmetakaraktärer kan appliceras på den. Så här ser det ut:

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


Gruppering av reguljära uttrycksfragment

I dessa exempel är ordet "nördar" inom parentes, följt av ett frågetecken. Kom ihåg att ett frågetecken betyder "0 eller 1 upprepning", så det reguljära uttrycket kommer att svara på både strängen "Gilla" och strängen "LikeGeeks".

Praktiska exempel

Nu när vi har täckt grunderna i reguljära uttryck är det dags att göra något användbart med dem.

▍Räknar antalet filer

Låt oss skriva ett bash-skript som räknar filer som finns i kataloger som är skrivna till miljövariabeln PATH. För att göra detta måste du först skapa en lista med katalogsökvägar. Låt oss göra detta med hjälp av sed, och ersätter kolon med mellanslag:

$ echo $PATH | sed "s/:/ /g"
Kommandot ersätt stöder reguljära uttryck som mönster för att söka text. I det här fallet är allt extremt enkelt, vi letar efter kolonsymbolen, men ingen stör oss att använda något annat här - allt beror på den specifika uppgiften.
Nu måste du gå igenom den resulterande listan i en slinga och utföra de åtgärder som krävs för att räkna antalet filer. Den allmänna konturen av skriptet kommer att se ut så här:

Mypath=$(echo $PATH | sed "s/:/ /g") för katalogen i $mypath gör klart
Låt oss nu skriva hela skriptets text genom att använda kommandot ls för att få information om antalet filer i varje katalog:

#!/bin/bash mypath=$(echo $PATH | sed "s/:/ /g") count=0 för katalog i $mypath do check=$(ls $katalog) för objekt i $check do count=$ [ $count + 1 ] klart echo "$directory - $count" count=0 gjort
När man kör skriptet kan det visa sig att vissa kataloger från PATH inte finns, men detta hindrar inte det från att räkna filer i befintliga kataloger.


Filräkning

Huvudvärdet av detta exempel är att med samma tillvägagångssätt kan du lösa mycket mer komplexa problem. Vilka exakt beror på dina behov.

▍Verifiera e-postadresser

Det finns webbplatser med enorma samlingar av reguljära uttryck som låter dig kontrollera e-postadresser, telefonnummer och så vidare. Det är dock en sak att ta något färdigt och en helt annan att skapa något själv. Så låt oss skriva ett reguljärt uttryck för att kontrollera e-postadresser. Låt oss börja med att analysera källdata. Här är till exempel en viss adress:

[e-postskyddad]
Användarnamnet, användarnamnet, kan bestå av alfanumeriska och några andra tecken. Detta är nämligen en prick, ett streck, ett understreck, ett plustecken. Användarnamnet följs av ett @-tecken.

Beväpnad med denna kunskap, låt oss börja sätta ihop det reguljära uttrycket från dess vänstra sida, som används för att kontrollera användarnamnet. Här är vad vi fick:

^(+)@
Detta reguljära uttryck kan läsas på följande sätt: "Roden måste börja med minst ett tecken från de i gruppen som anges inom hakparenteser, följt av ett @-tecken."

Nu - värdnamnet kö - värdnamn . Samma regler gäller här som för användarnamnet, så mallen för det kommer att se ut så här:

(+)
Toppdomännamnet omfattas av särskilda regler. Det kan bara finnas alfabetiska tecken, av vilka det måste finnas minst två (till exempel innehåller sådana domäner vanligtvis en landskod), och inte fler än fem. Allt detta betyder att mallen för att kontrollera den sista delen av adressen blir så här:

\.({2,5})$
Du kan läsa det så här: "Först måste det finnas en punkt, sedan 2 till 5 alfabetiska tecken, och efter det slutar raden."

Efter att ha förberett mallar för enskilda delar av det reguljära uttrycket, låt oss sätta ihop dem:

^(+)@(+)\.({2,5})$
Nu återstår bara att testa vad som hände:

$ echo" [e-postskyddad]" | awk "/^(+)@(+)\.((2,5))$/(print $0)" $ echo " [e-postskyddad]" | awk "/^(+)@(+)\.((2,5))$/(skriv ut $0)"


Validera en e-postadress med reguljära uttryck

Det faktum att texten som skickas till awk visas på skärmen betyder att systemet kände igen den som en e-postadress.

Resultat

Om det reguljära uttrycket för att kontrollera e-postadresser som du stötte på i början av artikeln verkade helt obegripligt då, hoppas vi att det nu inte längre ser ut som en meningslös uppsättning tecken. Om detta är sant, så har detta material uppfyllt sitt syfte. Faktum är att reguljära uttryck är ett ämne som du kan studera hela livet, men även det lilla som vi har täckt kan redan hjälpa dig att skriva manus som bearbetar texter ganska avancerade.

I den här serien av material visade vi vanligtvis mycket enkla exempel på bash-skript som bestod av bokstavligen några rader. Nästa gång ska vi titta på något större.

Kära läsare! Använder du reguljära uttryck när du bearbetar text i kommandoradsskript?

För att fullständigt bearbeta texter i bash-skript med sed och awk behöver du bara förstå reguljära uttryck. Implementeringar av detta mest användbara verktyg kan hittas bokstavligen överallt, och även om alla reguljära uttryck är strukturerade på ett liknande sätt och bygger på samma idéer, har det vissa funktioner att arbeta med dem i olika miljöer. Här kommer vi att prata om reguljära uttryck som är lämpliga för användning i Linux kommandoradsskript.

Detta material är tänkt som en introduktion till reguljära uttryck, avsett för dem som kanske är helt omedvetna om vad de är. Så låt oss börja från början.

Vad är reguljära uttryck

Många människor, när de först ser vanliga uttryck, tror genast att de tittar på ett meningslöst virrvarr av karaktärer. Men detta är naturligtvis långt ifrån fallet. Ta en titt på detta regex till exempel

Enligt vår mening kommer även en absolut nybörjare omedelbart att förstå hur det fungerar och varför det behövs :) Om du inte riktigt förstår det, läs bara vidare så faller allt på plats.
Ett reguljärt uttryck är ett mönster som program som sed eller awk använder för att filtrera text. Mallar använder vanliga ASCII-tecken som representerar sig själva, och så kallade metatecken som spelar en speciell roll, t.ex. tillåter referenser till vissa grupper av tecken.

Typer av reguljära uttryck

Implementeringar av reguljära uttryck i olika miljöer, till exempel i programmeringsspråk som Java, Perl och Python, och i Linux-verktyg som sed, awk och grep, har vissa funktioner. Dessa funktioner är beroende av så kallade reguljära uttrycksmotorer, som tolkar mönster.
Linux har två reguljära uttrycksmotorer:

  • En motor som stöder standarden POSIX Basic Regular Expression (BRE).
  • En motor som stöder standarden POSIX Extended Regular Expression (ERE).

De flesta Linux-verktyg överensstämmer med åtminstone POSIX BRE-standarden, men vissa verktyg (inklusive sed) förstår bara en delmängd av BRE-standarden. En av anledningarna till denna begränsning är önskan att göra sådana verktyg så snabbt som möjligt vid textbehandling.

POSIX ERE-standarden implementeras ofta i programmeringsspråk. Det låter dig använda ett stort antal verktyg när du utvecklar reguljära uttryck. Det kan till exempel vara speciella teckensekvenser för ofta använda mönster, som att söka efter enskilda ord eller uppsättningar av siffror i text. Awk stöder ERE-standarden.

Det finns många sätt att utveckla reguljära uttryck, beroende både på programmerarens åsikt och på funktionerna i motorn som de är skapade för. Det är inte lätt att skriva universella reguljära uttryck som vilken motor som helst kan förstå. Därför kommer vi att fokusera på de vanligaste reguljära uttrycken och titta på funktionerna i deras implementering för sed och awk.

POSIX BRE reguljära uttryck

Det kanske enklaste BRE-mönstret är ett reguljärt uttryck för att söka efter den exakta förekomsten av en sekvens av tecken i text. Så här ser det ut att söka efter en sträng i sed och awk:

$ echo "Detta är ett test" | sed -n "/test/p" $ echo "Detta är ett test" | awk "/test/(print $0)"

Hitta text efter mönster i sed

Hitta text efter mönster i awk

Du kanske märker att sökningen efter ett givet mönster utförs utan att ta hänsyn till den exakta platsen för texten i raden. Dessutom spelar antalet händelser ingen roll. Efter att det reguljära uttrycket hittar den angivna texten var som helst i strängen anses strängen vara lämplig och skickas vidare för vidare bearbetning.

När du arbetar med reguljära uttryck måste du ta hänsyn till att de är skiftlägeskänsliga:

$ echo "Detta är ett test" | awk "/Test/(print $0)" $ echo "Detta är ett test" | awk "/test/(print $0)"

Reguljära uttryck är skiftlägeskänsliga

Det första reguljära uttrycket hittade inga matchningar eftersom ordet "test", som börjar med en stor bokstav, inte förekommer i texten. Den andra, konfigurerad för att söka efter ett ord skrivet med versaler, hittade en lämplig rad i strömmen.

I reguljära uttryck kan du inte bara använda bokstäver utan även mellanslag och siffror:

$ echo "Detta är ett test 2 igen" | awk "/test 2/(print $0)"

Hitta ett stycke text som innehåller mellanslag och siffror

Mellanslag behandlas som vanliga tecken av motorn för reguljära uttryck.

Specialsymboler

När du använder olika tecken i reguljära uttryck finns det några saker att tänka på. Det finns alltså några specialtecken, eller metatecken, vars användning i en mall kräver ett speciellt tillvägagångssätt. Här är de:

.*^${}+?|()

Om en av dem behövs i mallen, kommer den att behöva escapes med ett snedstreck (omvänt snedstreck) - .

Om du till exempel behöver hitta ett dollartecken i texten måste du inkludera det i mallen, föregås av ett escape-tecken. Låt oss säga att det finns en fil myfile med följande text:

Det finns 10$ på min ficka

Dollartecknet kan upptäckas med detta mönster:

$awk "/$/(skriv ut $0)" min fil

Använda ett specialtecken i ett mönster

Dessutom är omvänt snedstreck också ett specialtecken, så om du behöver använda det i ett mönster kommer det också att behöva escapes. Det ser ut som två snedstreck som följer efter varandra:

$ echo "är ett specialtecken" | awk "/\/(skriv ut $0)"

Undviker ett snedstreck

Även om snedstrecket inte ingår i listan över specialtecken ovan, kommer ett försök att använda det i ett reguljärt uttryck skrivet för sed eller awk att resultera i ett fel:

Felaktig användning av snedstreck i ett mönster

Om det behövs måste det också undvikas:

$ echo "3/2" | awk "///(print $0)"

Undviker ett snedstreck framåt

Ankare symboler

Det finns två specialtecken för att länka ett mönster till början eller slutet av en textsträng. Captecknet - ^ låter dig beskriva sekvenser av tecken som finns i början av textrader. Om mönstret du letar efter finns någon annanstans i strängen, kommer det reguljära uttrycket inte att svara på det. Användningen av denna symbol ser ut så här:

$ echo "välkommen till likegeeks hemsida" | awk "/^likegeeks/(skriv ut $0)" $ echo "likegeeks hemsida" | awk "/^likegeeks/(skriv ut $0)"

Hitta ett mönster i början av en sträng

Tecknet ^ är utformat för att söka efter ett mönster i början av en rad, medan fallet med tecken också tas med i beräkningen. Låt oss se hur detta påverkar behandlingen av en textfil:

$awk "/^this/(skriv ut $0)" min fil


Hitta ett mönster i början av en rad i text från en fil

När du använder sed, om du placerar en keps någonstans inuti mönstret, kommer den att behandlas som vilken annan vanlig karaktär som helst:

$ echo "Detta ^ är ett test" | sed -n "/s ^/p"

Keps inte i början av mönstret i sed

I awk, när du använder samma mall, måste detta tecken escapes:

$ echo "Detta ^ är ett test" | awk "/s ^/(print $0)"

Täck inte i början av mallen i awk

Vi har listat ut sökningen efter textfragment som finns i början av en rad. Vad händer om du behöver hitta något i slutet av en rad?

Dollartecknet - $, som är ankartecknet för slutet av raden, hjälper oss med detta:

$ echo "Detta är ett test" | awk "/test$/(print $0)"

Hitta text i slutet av en rad

Du kan använda båda ankarsymbolerna i samma mall. Låt oss bearbeta filen myfile, vars innehåll visas i figuren nedan, med hjälp av följande reguljära uttryck:

$ awk "/^detta är en test$/(skriv ut $0)" min fil


Ett mönster som använder specialtecken för att starta och avsluta en rad

Som du kan se, svarade mallen endast på en rad som helt motsvarade den givna sekvensen av tecken och deras plats.

Så här filtrerar du bort tomma rader med ankartecken:

$awk "!/^$/(skriv ut $0)" min fil

I den här mallen använde jag en negationssymbol, ett utropstecken - ! . Genom att använda det här mönstret söker man efter linjer som inte innehåller någonting mellan början och slutet av raden, och tack vare utropstecken skrivs endast linjer som inte matchar detta mönster ut.

Punktsymbol

Perioden används för att matcha ett enskilt tecken utom nyradstecknet. Låt oss skicka filen myfile till detta reguljära uttryck, vars innehåll anges nedan:

$awk "/.st/(skriv ut $0)" min fil


Använder en punkt i reguljära uttryck

Som kan ses av utdata, motsvarar endast de två första raderna från filen mönstret, eftersom de innehåller sekvensen av tecken "st" föregås av ett annat tecken, medan den tredje raden inte innehåller en lämplig sekvens, och fjärde har det, men är med i början av raden.

Karaktärsklasser

En prick matchar varje enskilt tecken, men vad händer om du vill vara mer flexibel när det gäller att begränsa uppsättningen tecken du letar efter? I den här situationen kan du använda karaktärsklasser.

Tack vare detta tillvägagångssätt kan du organisera en sökning efter vilken karaktär som helst från en given uppsättning. För att beskriva en teckenklass används hakparenteser:

$awk "/th/(skriv ut $0)" min fil


Beskrivning av en teckenklass i ett reguljärt uttryck

Här letar vi efter en sekvens av "te" tecken som föregås av ett "o"-tecken eller ett "i"-tecken.

Klasser är praktiska när du söker efter ord som kan börja med antingen en stor eller liten bokstav:

$ echo "det här är ett test" | awk "/hans är ett test/(skriv ut $0)" $ echo "Detta är ett test" | awk "/hans är ett test/(skriv ut $0)"

Sök efter ord som kan börja med en liten eller stor bokstav

Karaktärsklasser är inte begränsade till bokstäver. Andra symboler kan användas här. Det är omöjligt att säga i förväg i vilken situation klasser kommer att behövas - allt beror på att problemet löses.

Negation av karaktärsklasser

Teckenklasser kan också användas för att lösa det omvända problemet som beskrivs ovan. Istället för att söka efter symboler som ingår i en klass kan du nämligen organisera en sökning efter allt som inte ingår i klassen. För att uppnå detta reguljära uttrycksbeteende måste du placera ett ^-tecken framför listan med klasstecken. Det ser ut så här:

$ awk "/[^oi]th/(print $0)" min fil


Hitta karaktärer som inte ingår i en klass

I det här fallet kommer sekvenser av "te" tecken att hittas som föregås av varken "o" eller "i".

Karaktärsintervall

I teckenklasser kan du beskriva teckenintervall med hjälp av bindestreck:

$awk "/st/(skriv ut $0)" min fil


Beskrivning av ett antal tecken i en teckenklass

I det här exemplet svarar det reguljära uttrycket på sekvensen av tecken "st" som föregås av ett tecken som är placerat, i alfabetisk ordning, mellan tecknen "e" och "p".

Områden kan också skapas från siffror:

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

Reguljärt uttryck för att hitta valfria tre tal

En teckenklass kan inkludera flera intervall:

$awk "/st/(skriv ut $0)" min fil


En teckenklass som består av flera intervall

Detta reguljära uttryck hittar alla sekvenser av "st" som föregås av tecken från intervallen a-f och m-z .

Specialkaraktärsklasser

BRE har speciella teckenklasser som du kan använda när du skriver reguljära uttryck:

  • [[:alpha:]] - matchar alla alfabetiska tecken, skrivna med stora eller små bokstäver.
  • [[:alnum:]] - matchar alla alfanumeriska tecken, nämligen tecken i intervallen 0-9 , A-Z , a-z .
  • [[:blank:]] - matchar ett mellanslag och ett tabbtecken.
  • [[:siffra:]] - valfritt tecken från 0 till 9.
  • [[:upper:]] - stora bokstäver - A-Z .
  • [[:lower:]] - små bokstäver - a-z .
  • [[:print:]] - matchar alla utskrivbara tecken.
  • [[:punct:]] - matchar skiljetecken.
  • [[:mellanslag:]] - blanksteg, i synnerhet - mellanslag, tab, tecken NL, FF, VT, CR.

Du kan använda specialklasser i mallar så här:

$ echo "abc" | awk "/[[:alpha:]]/(print $0)" $ echo "abc" | awk "/[[:digit:]]/(print $0)" $ echo "abc123" | awk "/[[:siffra:]]/(skriv ut $0)"


Specialteckenklasser i reguljära uttryck

Stjärnsymbol

Om du placerar en asterisk efter ett tecken i ett mönster kommer det att innebära att det reguljära uttrycket fungerar om tecknet förekommer i strängen hur många gånger som helst - inklusive situationen när tecknet saknas i strängen.

$ echo "test" | awk "/tes*t/(skriv ut $0)" $ echo "tessst" | awk "/tes*t/(skriv ut $0)"


Använda tecknet * i reguljära uttryck

Detta jokertecken används vanligtvis för ord som ständigt stavas fel, eller för ord som har olika stavningar:

$ echo "Jag gillar grön färg" | awk "/colou*r/(print $0)" $ echo "Jag gillar grön färg " | awk "/colou*r/(print $0)"

Hitta ett ord med olika stavningar

I det här exemplet svarar samma reguljära uttryck på både ordet "färg" och ordet "färg". Detta beror på det faktum att tecknet "u", följt av en asterisk, antingen kan vara frånvarande eller visas flera gånger i rad.

En annan användbar funktion som kommer från asterisksymbolen är att kombinera den med en prick. Denna kombination låter det reguljära uttrycket svara på valfritt antal tecken:

$ awk "/this.*test/(print $0)" min fil


En mall som svarar på valfritt antal tecken

I det här fallet spelar det ingen roll hur många och vilka tecken som finns mellan orden "detta" och "testa".

Asterisken kan också användas med teckenklasser:

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


Använda en asterisk med teckenklasser

I alla tre exemplen fungerar det reguljära uttrycket eftersom asterisken efter teckenklassen betyder att om valfritt antal "a" eller "e" tecken hittas, eller om inga hittas, kommer strängen att matcha det givna mönstret.

POSIX ERE reguljära uttryck

POSIX ERE-mallarna som vissa Linux-verktyg stöder kan innehålla ytterligare tecken. Som redan nämnts stöder awk denna standard, men sed gör det inte.

Här kommer vi att titta på de mest använda symbolerna i ERE-mönster, som kommer att vara användbara för dig när du skapar dina egna reguljära uttryck.

▍Frågetecken

Ett frågetecken anger att det föregående tecknet kan förekomma en gång eller inte alls i texten. Den här karaktären är en av upprepningsmetakaraktärerna. Här är några exempel:

$ echo "tet" | awk "/tes?t/(print $0)" $ echo "test" | awk "/tes?t/(print $0)" $ echo "testst" | awk "/tes?t/(print $0)"


Frågetecken i reguljära uttryck

Som du kan se, i det tredje fallet visas bokstaven "s" två gånger, så det reguljära uttrycket svarar inte på ordet "testst".

Frågetecknet kan också användas med teckenklasser:

$ echo "tst" | awk "/t?st/(print $0)" $ echo "test" | awk "/t?st/(print $0)" $ echo "tast" | awk "/t?st/(print $0)" $ echo "taest" | awk "/t?st/(print $0)" $ echo "test" | awk "/t?st/(print $0)"


Frågetecken och karaktärsklasser

Om det inte finns några tecken från klassen på raden, eller ett av dem förekommer en gång, fungerar det reguljära uttrycket, men så fort två tecken dyker upp i ordet hittar systemet inte längre en matchning för mönstret i texten.

▍Plussymbol

Plustecknet i mönstret anger att det reguljära uttrycket kommer att matcha det det letar efter om det föregående tecknet förekommer en eller flera gånger i texten. Denna konstruktion kommer dock inte att reagera på frånvaron av en symbol:

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


Plussymbolen i reguljära uttryck

I det här exemplet, om det inte finns något "e"-tecken i ordet, hittar inte motorn för reguljära uttryck matchningar med mönstret i texten. Plussymbolen fungerar också med teckenklasser - på så sätt liknar den asterisken och frågetecknet:

$ echo "tst" | awk "/t+st/(print $0)" $ echo "test" | awk "/t+st/(print $0)" $ echo "teast" | awk "/t+st/(print $0)" $ echo "teeast" | awk "/t+st/(print $0)"


Plus tecken och tecken klasser

I det här fallet, om raden innehåller något tecken från klassen, kommer texten att anses matcha mönstret.

▍Kulliga hängslen

Lockiga hängslen, som kan användas i ERE-mönster, liknar symbolerna som diskuterats ovan, men de låter dig mer exakt specificera det antal förekomster som krävs av symbolen som föregår dem. Du kan ange en begränsning i två format:

  • n - ett nummer som anger det exakta antalet sökta förekomster
  • n, m är två tal som tolkas enligt följande: "minst n gånger, men inte mer än m."

Här är exempel på det första alternativet:

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

Lockiga hängslen i mönster, söker efter det exakta antalet förekomster

I äldre versioner av awk var du tvungen att använda kommandoradsalternativet --re-interval för att få programmet att känna igen intervall i reguljära uttryck, men i nyare versioner är detta inte nödvändigt.

$ 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/(print $0)"


Avstånd specificerat i lockiga hängslen

I det här exemplet måste tecknet "e" visas 1 eller 2 gånger på raden, då kommer det reguljära uttrycket att svara på texten.

Lockiga hängslen kan också användas med karaktärsklasser. De principer du redan känner till gäller här:

$ echo "tst" | awk "/t(1,2)st/(print $0)" $ echo "test" | awk "/t(1,2)st/(print $0)" $ echo "test" | awk "/t(1,2)st/(print $0)" $ echo "teeast" | awk "/t(1,2)st/(print $0)"


Lockiga hängslen och karaktärsklasser

Mallen kommer att reagera på texten om den innehåller tecknet "a" eller tecknet "e" en eller två gånger.

▍Logisk "eller"-symbol

Symbol | - en vertikal stapel betyder ett logiskt "eller" i reguljära uttryck. Vid bearbetning av ett reguljärt uttryck som innehåller flera fragment åtskilda av ett sådant tecken, kommer motorn att anse den analyserade texten som lämplig om den matchar något av fragmenten. Här är ett exempel:

$ echo "Detta är ett test" | awk "/test|exam/(print $0)" $ echo "Detta är en tentamen" | awk "/test|exam/(print $0)" $ echo "Detta är något annat" | awk "/test|exam/(print $0)"


Logiskt "eller" i reguljära uttryck

I det här exemplet är det reguljära uttrycket konfigurerat för att söka i texten efter orden "test" eller "examen". Observera att mellan mallfragmenten och symbolen som skiljer dem | det ska inte finnas några mellanslag.

Reguljära uttrycksfragment kan grupperas med hjälp av parenteser. Om du grupperar en viss teckensekvens kommer den att uppfattas av systemet som en vanlig karaktär. Det vill säga att till exempel upprepningsmetakaraktärer kan appliceras på den. Så här ser det ut:

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


Gruppering av reguljära uttrycksfragment

I dessa exempel är ordet "nördar" inom parentes, följt av ett frågetecken. Kom ihåg att ett frågetecken betyder "0 eller 1 upprepning", så det reguljära uttrycket kommer att svara på både strängen "Gilla" och strängen "LikeGeeks".

Praktiska exempel

Nu när vi har täckt grunderna i reguljära uttryck är det dags att göra något användbart med dem.

▍Räknar antalet filer

Låt oss skriva ett bash-skript som räknar filer som finns i kataloger som är skrivna till miljövariabeln PATH. För att göra detta måste du först skapa en lista med katalogsökvägar. Låt oss göra detta med hjälp av sed, och ersätter kolon med mellanslag:

$ echo $PATH | sed "s/:/ /g"

Kommandot ersätt stöder reguljära uttryck som mönster för att söka text. I det här fallet är allt extremt enkelt, vi letar efter kolonsymbolen, men ingen stör oss att använda något annat här - allt beror på den specifika uppgiften.
Nu måste du gå igenom den resulterande listan i en slinga och utföra de åtgärder som krävs för att räkna antalet filer. Den allmänna konturen av skriptet kommer att se ut så här:

Mypath=$(echo $PATH | sed "s/:/ /g") för katalogen i $mypath gör klart

Låt oss nu skriva hela skriptets text genom att använda kommandot ls för att få information om antalet filer i varje katalog:

#!/bin/bash mypath=$(echo $PATH | sed "s/:/ /g") count=0 för katalog i $mypath do check=$(ls $katalog) för objekt i $check do count=$ [ $count + 1 ] klart echo "$directory - $count" count=0 gjort

När man kör skriptet kan det visa sig att vissa kataloger från PATH inte finns, men detta kommer inte att hindra det från att räkna filer i befintliga kataloger.


Filräkning

Huvudvärdet av detta exempel är att med samma tillvägagångssätt kan du lösa mycket mer komplexa problem. Vilka exakt beror på dina behov.

▍Verifiera e-postadresser

Det finns webbplatser med enorma samlingar av reguljära uttryck som låter dig kontrollera e-postadresser, telefonnummer och så vidare. Det är dock en sak att ta något färdigt och en helt annan att skapa något själv. Så låt oss skriva ett reguljärt uttryck för att kontrollera e-postadresser. Låt oss börja med att analysera källdata. Här är till exempel en viss adress:

[e-postskyddad]

Användarnamnet, användarnamnet, kan bestå av alfanumeriska och några andra tecken. Detta är nämligen en prick, ett streck, ett understreck, ett plustecken. Användarnamnet följs av ett @-tecken.

Beväpnad med denna kunskap, låt oss börja sätta ihop det reguljära uttrycket från dess vänstra sida, som används för att kontrollera användarnamnet. Här är vad vi fick:

^(+)@

Nu - värdnamnet kö - värdnamn . Samma regler gäller här som för användarnamnet, så mallen för det kommer att se ut så här:

(+)

Toppdomännamnet omfattas av särskilda regler. Det kan bara finnas alfabetiska tecken, av vilka det måste finnas minst två (till exempel innehåller sådana domäner vanligtvis en landskod), och inte fler än fem. Allt detta betyder att mallen för att kontrollera den sista delen av adressen blir så här:

.({2,5})$

Du kan läsa det så här: "Först måste det finnas en punkt, sedan 2 till 5 alfabetiska tecken, och efter det slutar raden."

Efter att ha förberett mallar för enskilda delar av det reguljära uttrycket, låt oss sätta ihop dem:

^(+)@(+).({2,5})$

Nu återstår bara att testa vad som hände:

$ echo" [e-postskyddad]" | awk "/^(+)@(+).((2,5))$/(print $0)" $ echo " [e-postskyddad]" | awk "/^(+)@(+).((2,5))$/(skriv ut $0)"


Validera en e-postadress med reguljära uttryck

Det faktum att texten som skickas till awk visas på skärmen betyder att systemet kände igen den som en e-postadress.

Resultat

Om det reguljära uttrycket för att kontrollera e-postadresser som du stötte på i början av artikeln verkade helt obegripligt då, hoppas vi att det nu inte längre ser ut som en meningslös uppsättning tecken. Om detta är sant, så har detta material uppfyllt sitt syfte. Faktum är att reguljära uttryck är ett ämne som du kan studera hela livet, men även det lilla som vi har täckt kan redan hjälpa dig att skriva manus som bearbetar texter ganska avancerade.

I den här serien av material visade vi vanligtvis mycket enkla exempel på bash-skript som bestod av bokstavligen några rader. Nästa gång ska vi titta på något större.

Kära läsare! Använder du reguljära uttryck när du bearbetar text i kommandoradsskript?

Vanligt uttryck- ett textmönster som består av en kombination av bokstäver, siffror och specialtecken som kallas metatecken. En nära släkting till reguljära uttryck är jokerteckenuttryck, som ofta används i filhantering. Reguljära uttryck används främst för textjämförelse och sökning. Används ofta för syntaxanalys.

UNIX-användare är bekanta med reguljära uttryck från grep, sed, awk (eller gawk) och ed. Med hjälp av dessa program eller deras analoger kan du prova och kontrollera exemplen nedan. Textredigerare som (X)Emacs och vi använder också mycket reguljära uttryck. Den kanske mest kända och mest utbredda användningen av reguljära uttryck förekommer i Perl-språket. Det är svårt för programutvecklare och systemadministratörer att klara sig utan kunskap om reguljära uttryck.

Metakaraktärer

Så strängar kan bestå av bokstäver, siffror och metatecken. Metakaraktärer är:

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

Metatecken kan spela följande roller i ett reguljärt uttryck:

    kvantifierare

    påstående;

    grupptecken;

    alternativ;

    sekvenstecken

Kvantifierare

Metatecken * (asterisk) ersätter 0 eller fler tecken. Metatecken + (plus) ersätter 1 eller fler tecken. Metakaraktär. (punkt) ersätter exakt 1 godtyckligt tecken. Metkaraktär? (frågetecken) ersätter 0 eller 1 tecken. Skillnaden i användningen av * och + är sådan att en fråga för strängen c* kommer att returnera alla strängar, inklusive tomma, medan en fråga med c+ endast returnerar strängar som innehåller tecknet c.

Tomma rader följer följande konventioner: en tom rad innehåller en och endast en tom rad; i en icke-tom sträng finns tomma rader före varje tecken och även i slutet av raden.

Reguljära uttryck använder också konstruktionen (n,m), vilket innebär att tecknet före konstruktionen förekommer n till m gånger på raden. Genom att utelämna talet m menar vi oändlighet. De där. specialfall av konstruktionen är följande poster: (0,), (1,) och (0,1) . Den första matchar *, den andra matchar metatecken + och den tredje matchar ? . Dessa likheter kan lätt erhållas från definitionen av motsvarande kvantifierare. Dessutom innebär konstruktionen (n) att symbolen dyker upp exakt n gånger.

I samband med användningen av vissa skiljetecken och matematiska symboler som metatecken har ytterligare ett metatecken \ (omvänt snedstreck) införts, som när det skrivs före ett metatecken gör det senare till ett vanligt tecken. De där. ? är en kvantifierare och \? - frågetecken.

Grupper

De ovan beskrivna kvantifierarna verkar, som redan nämnts, på symbolen närmast dem till vänster (den sista föregående). Men denna begränsning kan kringgås av grupper som använder metatecken (och) i sina beteckningar. Dessa symboler skiljer ut ett underuttryck från ett uttryck, som kombineras till en grupp, på vilken kvantifieraren sedan appliceras.

Exempel:

betyder (eller ersätter)

Ho ho ho ho ho ho ho hohoho

Kapslingar av deluttryck är möjliga, d.v.s. Deluttryck med kortare längd kan extraheras från ett deluttryck.

Alternativ

Bildas med metasymbolen | (vertikal stapel) som anger logiskt "eller".

Exempel: reguljära uttryck cows(a|s|e|y|oh|oh)? specificerar alla möjliga böjningar av ordet "ko" i singular för fall.

Uttalanden

Metatecken identifieras som betecknar speciella objekt - linjer med noll längd som tjänar till att bestämma platsen för texten som föregår eller följer dem. Sådana objekt kallas påståenden. Följande påståenden finns i reguljära uttryck:

^ början av raden $ slutet av raden< начало слова >slutet av ordet

Exempel: Det reguljära uttrycket $The matchar en sträng som börjar med The .

Obs: Vanliga tecken kan behandlas som påståenden med en längd som inte är noll.

Sekvenser

En speciell konstruktion innesluten i metatecken [ och ] (rektangulära parenteser) låter dig lista varianter av tecken som kan förekomma i ett reguljärt uttryck på en given plats, och kallas en sekvens. Inom rektangulära parenteser behandlas alla metatecken som enkla tecken, och symbolerna - (minus) och ^ får nya betydelser: den första låter dig ange en kontinuerlig sekvens av tecken mellan två specificerade tecken, och den andra ger ett logiskt "inte ” (negation). Det är lättast att överväga följande exempel:

någon av de små latinska bokstäverna:

Latinskt alfanumeriskt tecken (från a till z, från A till Ö och från 0 till 9):

icke-latinska alfanumeriska tecken:

[^a-zA-Z0-9]

vilket ord som helst (utan bindestreck, matematiska symboler och siffror):

<+>

För korthet och enkelhet introduceras följande förkortningar:

\d siffra (dvs. motsvarar uttrycket); \D är inte en siffra (dvs [^0-9]); \w latinskt ord (alfanumeriskt); \W är en sekvens av tecken utan mellanslag som inte är ett latinskt alfanumeriskt ord ([^a-zA-Z0-9]); \s tomt utrymme [ \t\n\r\f], dvs. mellanslag, flikar osv. \S icke-tomt intervall ([^ \t\n\r\f]).

Förhållande med jokertecken

Förmodligen är alla användare bekanta med jokertecken. Ett exempel på ett jokerteckenuttryck är *.jpg, som representerar alla filer med filtillägget jpg. Hur skiljer sig reguljära uttryck från jokertecken? Skillnaderna kan sammanfattas i tre regler för att konvertera ett godtyckligt uttryck med jokertecken till ett reguljärt uttryck:

    Ersatt av.*

    Byta ut? på.

    Byt ut alla karaktärer som matchar metakaraktärer med deras omvänt snedstreckade versioner.

Faktum är att i ett reguljärt uttryck är posten * värdelös och producerar en tom sträng, eftersom innebär att den tomma raden upprepas så många gånger som önskas. Men * (upprepa en godtycklig symbol så många gånger du vill, inklusive 0) sammanfaller exakt i betydelse med symbolen * i uppsättningen jokertecken.

Ett reguljärt uttryck som matchar *.jpg skulle se ut så här: .*\.jpg . Och, till exempel, sekvensen av jokertecken ez*.pp motsvarar två ekvivalenta reguljära uttryck - ez.*\.pp och ez.*\.(cpp|hpp) .

Exempel på reguljära uttryck

E-postformat [e-postskyddad]

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

E-post i formatet "Ivan Ivanov "

("?+"?[ \t]*)+\<+(\.+)*@+(\.+)+\>

Kontrollera webbprotokollet i URL:en (http://, ftp:// eller https://)

+://

Vissa C/C++ kommandon och direktiv:

^#inkludera[ \t]+[<"][^>"]+[">] - inkludera direktiv

//.+$ - kommentar på en rad

/\*[^*]*\*/ - kommentera flera rader

-?+\.+ - flyttalnummer

0x+ är ett tal i det hexadecimala talsystemet.

Och här är till exempel ett program för att söka efter ordet ko:

grep -E "cow|vache" * >/ dev/ null && echo "Hittade en ko"

Här används alternativet -E för att aktivera stöd för utökad syntax för reguljära uttryck.

Texten bygger på en artikel av Jan Borsodi från filen HOWTO-regexps.htm

För att fullständigt bearbeta texter i bash-skript med sed och awk behöver du bara förstå reguljära uttryck. Implementeringar av detta mest användbara verktyg kan hittas bokstavligen överallt, och även om alla reguljära uttryck är strukturerade på ett liknande sätt och bygger på samma idéer, har det vissa funktioner att arbeta med dem i olika miljöer. Här kommer vi att prata om reguljära uttryck som är lämpliga för användning i Linux kommandoradsskript.

Detta material är tänkt som en introduktion till reguljära uttryck, avsett för dem som kanske är helt omedvetna om vad de är. Så låt oss börja från början.

Vad är reguljära uttryck

Många människor, när de först ser vanliga uttryck, tror genast att de tittar på ett meningslöst virrvarr av karaktärer. Men detta är naturligtvis långt ifrån fallet. Ta en titt på detta regex till exempel


Enligt vår mening kommer även en absolut nybörjare omedelbart att förstå hur det fungerar och varför det behövs :) Om du inte riktigt förstår det, läs bara vidare så faller allt på plats.
Ett reguljärt uttryck är ett mönster som program som sed eller awk använder för att filtrera text. Mallar använder vanliga ASCII-tecken som representerar sig själva, och så kallade metatecken som spelar en speciell roll, t.ex. tillåter referenser till vissa grupper av tecken.

Typer av reguljära uttryck

Implementeringar av reguljära uttryck i olika miljöer, till exempel i programmeringsspråk som Java, Perl och Python, och i Linux-verktyg som sed, awk och grep, har vissa funktioner. Dessa funktioner är beroende av så kallade reguljära uttrycksmotorer, som tolkar mönster.
Linux har två reguljära uttrycksmotorer:
  • En motor som stöder standarden POSIX Basic Regular Expression (BRE).
  • En motor som stöder standarden POSIX Extended Regular Expression (ERE).
De flesta Linux-verktyg överensstämmer med åtminstone POSIX BRE-standarden, men vissa verktyg (inklusive sed) förstår bara en delmängd av BRE-standarden. En av anledningarna till denna begränsning är önskan att göra sådana verktyg så snabbt som möjligt vid textbehandling.

POSIX ERE-standarden implementeras ofta i programmeringsspråk. Det låter dig använda ett stort antal verktyg när du utvecklar reguljära uttryck. Det kan till exempel vara speciella teckensekvenser för ofta använda mönster, som att söka efter enskilda ord eller uppsättningar av siffror i text. Awk stöder ERE-standarden.

Det finns många sätt att utveckla reguljära uttryck, beroende både på programmerarens åsikt och på funktionerna i motorn som de är skapade för. Det är inte lätt att skriva universella reguljära uttryck som vilken motor som helst kan förstå. Därför kommer vi att fokusera på de vanligaste reguljära uttrycken och titta på funktionerna i deras implementering för sed och awk.

POSIX BRE reguljära uttryck

Det kanske enklaste BRE-mönstret är ett reguljärt uttryck för att söka efter den exakta förekomsten av en sekvens av tecken i text. Så här ser det ut att söka efter en sträng i sed och awk:

$ echo "Detta är ett test" | sed -n "/test/p" $ echo "Detta är ett test" | awk "/test/(print $0)"

Hitta text efter mönster i sed


Hitta text efter mönster i awk

Du kanske märker att sökningen efter ett givet mönster utförs utan att ta hänsyn till den exakta platsen för texten i raden. Dessutom spelar antalet händelser ingen roll. Efter att det reguljära uttrycket hittar den angivna texten var som helst i strängen anses strängen vara lämplig och skickas vidare för vidare bearbetning.

När du arbetar med reguljära uttryck måste du ta hänsyn till att de är skiftlägeskänsliga:

$ echo "Detta är ett test" | awk "/Test/(print $0)" $ echo "Detta är ett test" | awk "/test/(print $0)"

Reguljära uttryck är skiftlägeskänsliga

Det första reguljära uttrycket hittade inga matchningar eftersom ordet "test", som börjar med en stor bokstav, inte förekommer i texten. Den andra, konfigurerad för att söka efter ett ord skrivet med versaler, hittade en lämplig rad i strömmen.

I reguljära uttryck kan du inte bara använda bokstäver utan även mellanslag och siffror:

$ echo "Detta är ett test 2 igen" | awk "/test 2/(print $0)"

Hitta ett stycke text som innehåller mellanslag och siffror

Mellanslag behandlas som vanliga tecken av motorn för reguljära uttryck.

Specialsymboler

När du använder olika tecken i reguljära uttryck finns det några saker att tänka på. Det finns alltså några specialtecken, eller metatecken, vars användning i en mall kräver ett speciellt tillvägagångssätt. Här är de:

.*^${}\+?|()
Om en av dem behövs i mallen, kommer den att behöva escapes med ett snedstreck (omvänt snedstreck) - \ .

Om du till exempel behöver hitta ett dollartecken i texten måste du inkludera det i mallen, föregås av ett escape-tecken. Låt oss säga att det finns en fil myfile med följande text:

Det finns 10$ på min ficka
Dollartecknet kan upptäckas med detta mönster:

$awk "/\$/(skriv ut $0)" min fil

Använda ett specialtecken i ett mönster

Dessutom är omvänt snedstreck också ett specialtecken, så om du behöver använda det i ett mönster kommer det också att behöva escapes. Det ser ut som två snedstreck som följer efter varandra:

$ echo "\ är ett specialtecken" | awk "/\\/(skriv ut $0)"

Undviker ett snedstreck

Även om snedstrecket inte ingår i listan över specialtecken ovan, kommer ett försök att använda det i ett reguljärt uttryck skrivet för sed eller awk att resultera i ett fel:

$ echo "3/2" | awk "///(print $0)"

Felaktig användning av snedstreck i ett mönster

Om det behövs måste det också undvikas:

$ echo "3/2" | awk "/\//(skriv ut $0)"

Undviker ett snedstreck framåt

Ankare symboler

Det finns två specialtecken för att länka ett mönster till början eller slutet av en textsträng. Captecknet - ^ låter dig beskriva sekvenser av tecken som finns i början av textrader. Om mönstret du letar efter finns någon annanstans i strängen, kommer det reguljära uttrycket inte att svara på det. Användningen av denna symbol ser ut så här:

$ echo "välkommen till likegeeks hemsida" | awk "/^likegeeks/(skriv ut $0)" $ echo "likegeeks hemsida" | awk "/^likegeeks/(skriv ut $0)"

Hitta ett mönster i början av en sträng

Tecknet ^ är utformat för att söka efter ett mönster i början av en rad, medan fallet med tecken också tas med i beräkningen. Låt oss se hur detta påverkar behandlingen av en textfil:

$awk "/^this/(skriv ut $0)" min fil


Hitta ett mönster i början av en rad i text från en fil

När du använder sed, om du placerar en keps någonstans inuti mönstret, kommer den att behandlas som vilken annan vanlig karaktär som helst:

$ echo "Detta ^ är ett test" | sed -n "/s ^/p"

Keps inte i början av mönstret i sed

I awk, när du använder samma mall, måste detta tecken escapes:

$ echo "Detta ^ är ett test" | awk "/s\^/(skriv ut $0)"

Täck inte i början av mallen i awk

Vi har listat ut sökningen efter textfragment som finns i början av en rad. Vad händer om du behöver hitta något i slutet av en rad?

Dollartecknet - $, som är ankartecknet för slutet av raden, hjälper oss med detta:

$ echo "Detta är ett test" | awk "/test$/(print $0)"

Hitta text i slutet av en rad

Du kan använda båda ankarsymbolerna i samma mall. Låt oss bearbeta filen myfile, vars innehåll visas i figuren nedan, med hjälp av följande reguljära uttryck:

$ awk "/^detta är en test$/(skriv ut $0)" min fil


Ett mönster som använder specialtecken för att starta och avsluta en rad

Som du kan se, svarade mallen endast på en rad som helt motsvarade den givna sekvensen av tecken och deras plats.

Så här filtrerar du bort tomma rader med ankartecken:

$awk "!/^$/(skriv ut $0)" min fil
I den här mallen använde jag en negationssymbol, ett utropstecken - ! . Genom att använda det här mönstret söker man efter linjer som inte innehåller någonting mellan början och slutet av raden, och tack vare utropstecken skrivs endast linjer som inte matchar detta mönster ut.

Punktsymbol

Perioden används för att matcha ett enskilt tecken utom nyradstecknet. Låt oss skicka filen myfile till detta reguljära uttryck, vars innehåll anges nedan:

$awk "/.st/(skriv ut $0)" min fil


Använder en punkt i reguljära uttryck

Som kan ses av utdata, motsvarar endast de två första raderna från filen mönstret, eftersom de innehåller sekvensen av tecken "st" föregås av ett annat tecken, medan den tredje raden inte innehåller en lämplig sekvens, och fjärde har det, men är med i början av raden.

Karaktärsklasser

En prick matchar varje enskilt tecken, men vad händer om du vill vara mer flexibel när det gäller att begränsa uppsättningen tecken du letar efter? I den här situationen kan du använda karaktärsklasser.

Tack vare detta tillvägagångssätt kan du organisera en sökning efter vilken karaktär som helst från en given uppsättning. För att beskriva en teckenklass används hakparenteser:

$awk "/th/(skriv ut $0)" min fil


Beskrivning av en teckenklass i ett reguljärt uttryck

Här letar vi efter en sekvens av "te" tecken som föregås av ett "o"-tecken eller ett "i"-tecken.

Klasser är praktiska när du söker efter ord som kan börja med antingen en stor eller liten bokstav:

$ echo "det här är ett test" | awk "/hans är ett test/(skriv ut $0)" $ echo "Detta är ett test" | awk "/hans är ett test/(skriv ut $0)"

Sök efter ord som kan börja med en liten eller stor bokstav

Karaktärsklasser är inte begränsade till bokstäver. Andra symboler kan användas här. Det är omöjligt att säga i förväg i vilken situation klasser kommer att behövas - allt beror på att problemet löses.

Negation av karaktärsklasser

Teckenklasser kan också användas för att lösa det omvända problemet som beskrivs ovan. Istället för att söka efter symboler som ingår i en klass kan du nämligen organisera en sökning efter allt som inte ingår i klassen. För att uppnå detta reguljära uttrycksbeteende måste du placera ett ^-tecken framför listan med klasstecken. Det ser ut så här:

$ awk "/[^oi]th/(print $0)" min fil


Hitta karaktärer som inte ingår i en klass

I det här fallet kommer sekvenser av "te" tecken att hittas som föregås av varken "o" eller "i".

Karaktärsintervall

I teckenklasser kan du beskriva teckenintervall med hjälp av bindestreck:

$awk "/st/(skriv ut $0)" min fil


Beskrivning av ett antal tecken i en teckenklass

I det här exemplet svarar det reguljära uttrycket på sekvensen av tecken "st" som föregås av ett tecken som är placerat, i alfabetisk ordning, mellan tecknen "e" och "p".

Områden kan också skapas från siffror:

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

Reguljärt uttryck för att hitta valfria tre tal

En teckenklass kan inkludera flera intervall:

$awk "/st/(skriv ut $0)" min fil


En teckenklass som består av flera intervall

Detta reguljära uttryck hittar alla sekvenser av "st" som föregås av tecken från intervallen a-f och m-z .

Specialkaraktärsklasser

BRE har speciella teckenklasser som du kan använda när du skriver reguljära uttryck:
  • [[:alpha:]] - matchar alla alfabetiska tecken, skrivna med stora eller små bokstäver.
  • [[:alnum:]] - matchar alla alfanumeriska tecken, nämligen tecken i intervallen 0-9 , A-Z , a-z .
  • [[:blank:]] - matchar ett mellanslag och ett tabbtecken.
  • [[:siffra:]] - valfritt tecken från 0 till 9.
  • [[:upper:]] - stora bokstäver - A-Z .
  • [[:lower:]] - små bokstäver - a-z .
  • [[:print:]] - matchar alla utskrivbara tecken.
  • [[:punct:]] - matchar skiljetecken.
  • [[:mellanslag:]] - blanksteg, i synnerhet - mellanslag, tab, tecken NL, FF, VT, CR.
Du kan använda specialklasser i mallar så här:

$ echo "abc" | awk "/[[:alpha:]]/(print $0)" $ echo "abc" | awk "/[[:digit:]]/(print $0)" $ echo "abc123" | awk "/[[:siffra:]]/(skriv ut $0)"


Specialteckenklasser i reguljära uttryck

Stjärnsymbol

Om du placerar en asterisk efter ett tecken i ett mönster kommer det att innebära att det reguljära uttrycket fungerar om tecknet förekommer i strängen hur många gånger som helst - inklusive situationen när tecknet saknas i strängen.

$ echo "test" | awk "/tes*t/(skriv ut $0)" $ echo "tessst" | awk "/tes*t/(skriv ut $0)"


Använda tecknet * i reguljära uttryck

Detta jokertecken används vanligtvis för ord som ständigt stavas fel, eller för ord som har olika stavningar:

$ echo "Jag gillar grön färg" | awk "/colou*r/(print $0)" $ echo "Jag gillar grön färg " | awk "/colou*r/(print $0)"

Hitta ett ord med olika stavningar

I det här exemplet svarar samma reguljära uttryck på både ordet "färg" och ordet "färg". Detta beror på det faktum att tecknet "u", följt av en asterisk, antingen kan vara frånvarande eller visas flera gånger i rad.

En annan användbar funktion som kommer från asterisksymbolen är att kombinera den med en prick. Denna kombination låter det reguljära uttrycket svara på valfritt antal tecken:

$ awk "/this.*test/(print $0)" min fil


En mall som svarar på valfritt antal tecken

I det här fallet spelar det ingen roll hur många och vilka tecken som finns mellan orden "detta" och "testa".

Asterisken kan också användas med teckenklasser:

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


Använda en asterisk med teckenklasser

I alla tre exemplen fungerar det reguljära uttrycket eftersom asterisken efter teckenklassen betyder att om valfritt antal "a" eller "e" tecken hittas, eller om inga hittas, kommer strängen att matcha det givna mönstret.

POSIX ERE reguljära uttryck

POSIX ERE-mallarna som vissa Linux-verktyg stöder kan innehålla ytterligare tecken. Som redan nämnts stöder awk denna standard, men sed gör det inte.

Här kommer vi att titta på de mest använda symbolerna i ERE-mönster, som kommer att vara användbara för dig när du skapar dina egna reguljära uttryck.

▍Frågetecken

Ett frågetecken anger att det föregående tecknet kan förekomma en gång eller inte alls i texten. Den här karaktären är en av upprepningsmetakaraktärerna. Här är några exempel:

$ echo "tet" | awk "/tes?t/(print $0)" $ echo "test" | awk "/tes?t/(print $0)" $ echo "testst" | awk "/tes?t/(print $0)"


Frågetecken i reguljära uttryck

Som du kan se, i det tredje fallet visas bokstaven "s" två gånger, så det reguljära uttrycket svarar inte på ordet "testst".

Frågetecknet kan också användas med teckenklasser:

$ echo "tst" | awk "/t?st/(print $0)" $ echo "test" | awk "/t?st/(print $0)" $ echo "tast" | awk "/t?st/(print $0)" $ echo "taest" | awk "/t?st/(print $0)" $ echo "test" | awk "/t?st/(print $0)"


Frågetecken och karaktärsklasser

Om det inte finns några tecken från klassen på raden, eller ett av dem förekommer en gång, fungerar det reguljära uttrycket, men så fort två tecken dyker upp i ordet hittar systemet inte längre en matchning för mönstret i texten.

▍Plussymbol

Plustecknet i mönstret anger att det reguljära uttrycket kommer att matcha det det letar efter om det föregående tecknet förekommer en eller flera gånger i texten. Denna konstruktion kommer dock inte att reagera på frånvaron av en symbol:

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


Plussymbolen i reguljära uttryck

I det här exemplet, om det inte finns något "e"-tecken i ordet, hittar inte motorn för reguljära uttryck matchningar med mönstret i texten. Plussymbolen fungerar också med teckenklasser - på så sätt liknar den asterisken och frågetecknet:

$ echo "tst" | awk "/t+st/(print $0)" $ echo "test" | awk "/t+st/(print $0)" $ echo "teast" | awk "/t+st/(print $0)" $ echo "teeast" | awk "/t+st/(print $0)"


Plus tecken och tecken klasser

I det här fallet, om raden innehåller något tecken från klassen, kommer texten att anses matcha mönstret.

▍Kulliga hängslen

Lockiga hängslen, som kan användas i ERE-mönster, liknar symbolerna som diskuterats ovan, men de låter dig mer exakt specificera det antal förekomster som krävs av symbolen som föregår dem. Du kan ange en begränsning i två format:
  • n - ett nummer som anger det exakta antalet sökta förekomster
  • n, m är två tal som tolkas enligt följande: "minst n gånger, men inte mer än m."
Här är exempel på det första alternativet:

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

Lockiga hängslen i mönster, söker efter det exakta antalet förekomster

I äldre versioner av awk var du tvungen att använda kommandoradsalternativet --re-interval för att få programmet att känna igen intervall i reguljära uttryck, men i nyare versioner är detta inte nödvändigt.

$ 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/(print $0)"


Avstånd specificerat i lockiga hängslen

I det här exemplet måste tecknet "e" visas 1 eller 2 gånger på raden, då kommer det reguljära uttrycket att svara på texten.

Lockiga hängslen kan också användas med karaktärsklasser. De principer du redan känner till gäller här:

$ echo "tst" | awk "/t(1,2)st/(print $0)" $ echo "test" | awk "/t(1,2)st/(print $0)" $ echo "test" | awk "/t(1,2)st/(print $0)" $ echo "teeast" | awk "/t(1,2)st/(print $0)"


Lockiga hängslen och karaktärsklasser

Mallen kommer att reagera på texten om den innehåller tecknet "a" eller tecknet "e" en eller två gånger.

▍Logisk "eller"-symbol

Symbol | - en vertikal stapel betyder ett logiskt "eller" i reguljära uttryck. Vid bearbetning av ett reguljärt uttryck som innehåller flera fragment åtskilda av ett sådant tecken, kommer motorn att anse den analyserade texten som lämplig om den matchar något av fragmenten. Här är ett exempel:

$ echo "Detta är ett test" | awk "/test|exam/(print $0)" $ echo "Detta är en tentamen" | awk "/test|exam/(print $0)" $ echo "Detta är något annat" | awk "/test|exam/(print $0)"


Logiskt "eller" i reguljära uttryck

I det här exemplet är det reguljära uttrycket konfigurerat för att söka i texten efter orden "test" eller "examen". Observera att mellan mallfragmenten och symbolen som skiljer dem | det ska inte finnas några mellanslag.

Reguljära uttrycksfragment kan grupperas med hjälp av parenteser. Om du grupperar en viss teckensekvens kommer den att uppfattas av systemet som en vanlig karaktär. Det vill säga att till exempel upprepningsmetakaraktärer kan appliceras på den. Så här ser det ut:

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


Gruppering av reguljära uttrycksfragment

I dessa exempel är ordet "nördar" inom parentes, följt av ett frågetecken. Kom ihåg att ett frågetecken betyder "0 eller 1 upprepning", så det reguljära uttrycket kommer att svara på både strängen "Gilla" och strängen "LikeGeeks".

Praktiska exempel

Nu när vi har täckt grunderna i reguljära uttryck är det dags att göra något användbart med dem.

▍Räknar antalet filer

Låt oss skriva ett bash-skript som räknar filer som finns i kataloger som är skrivna till miljövariabeln PATH. För att göra detta måste du först skapa en lista med katalogsökvägar. Låt oss göra detta med hjälp av sed, och ersätter kolon med mellanslag:

$ echo $PATH | sed "s/:/ /g"
Kommandot ersätt stöder reguljära uttryck som mönster för att söka text. I det här fallet är allt extremt enkelt, vi letar efter kolonsymbolen, men ingen stör oss att använda något annat här - allt beror på den specifika uppgiften.
Nu måste du gå igenom den resulterande listan i en slinga och utföra de åtgärder som krävs för att räkna antalet filer. Den allmänna konturen av skriptet kommer att se ut så här:

Mypath=$(echo $PATH | sed "s/:/ /g") för katalogen i $mypath gör klart
Låt oss nu skriva hela skriptets text genom att använda kommandot ls för att få information om antalet filer i varje katalog:

#!/bin/bash mypath=$(echo $PATH | sed "s/:/ /g") count=0 för katalog i $mypath do check=$(ls $katalog) för objekt i $check do count=$ [ $count + 1 ] klart echo "$directory - $count" count=0 gjort
När man kör skriptet kan det visa sig att vissa kataloger från PATH inte finns, men detta hindrar inte det från att räkna filer i befintliga kataloger.


Filräkning

Huvudvärdet av detta exempel är att med samma tillvägagångssätt kan du lösa mycket mer komplexa problem. Vilka exakt beror på dina behov.

▍Verifiera e-postadresser

Det finns webbplatser med enorma samlingar av reguljära uttryck som låter dig kontrollera e-postadresser, telefonnummer och så vidare. Det är dock en sak att ta något färdigt och en helt annan att skapa något själv. Så låt oss skriva ett reguljärt uttryck för att kontrollera e-postadresser. Låt oss börja med att analysera källdata. Här är till exempel en viss adress:

[e-postskyddad]
Användarnamnet, användarnamnet, kan bestå av alfanumeriska och några andra tecken. Detta är nämligen en prick, ett streck, ett understreck, ett plustecken. Användarnamnet följs av ett @-tecken.

Beväpnad med denna kunskap, låt oss börja sätta ihop det reguljära uttrycket från dess vänstra sida, som används för att kontrollera användarnamnet. Här är vad vi fick:

^(+)@
Detta reguljära uttryck kan läsas på följande sätt: "Roden måste börja med minst ett tecken från de i gruppen som anges inom hakparenteser, följt av ett @-tecken."

Nu - värdnamnet kö - värdnamn . Samma regler gäller här som för användarnamnet, så mallen för det kommer att se ut så här:

(+)
Toppdomännamnet omfattas av särskilda regler. Det kan bara finnas alfabetiska tecken, av vilka det måste finnas minst två (till exempel innehåller sådana domäner vanligtvis en landskod), och inte fler än fem. Allt detta betyder att mallen för att kontrollera den sista delen av adressen blir så här:

\.({2,5})$
Du kan läsa det så här: "Först måste det finnas en punkt, sedan 2 till 5 alfabetiska tecken, och efter det slutar raden."

Efter att ha förberett mallar för enskilda delar av det reguljära uttrycket, låt oss sätta ihop dem:

^(+)@(+)\.({2,5})$
Nu återstår bara att testa vad som hände:

$ echo" [e-postskyddad]" | awk "/^(+)@(+)\.((2,5))$/(print $0)" $ echo " [e-postskyddad]" | awk "/^(+)@(+)\.((2,5))$/(skriv ut $0)"


Validera en e-postadress med reguljära uttryck

Det faktum att texten som skickas till awk visas på skärmen betyder att systemet kände igen den som en e-postadress.

Resultat

Om det reguljära uttrycket för att kontrollera e-postadresser som du stötte på i början av artikeln verkade helt obegripligt då, hoppas vi att det nu inte längre ser ut som en meningslös uppsättning tecken. Om detta är sant, så har detta material uppfyllt sitt syfte. Faktum är att reguljära uttryck är ett ämne som du kan studera hela livet, men även det lilla som vi har täckt kan redan hjälpa dig att skriva manus som bearbetar texter ganska avancerade.

I den här serien av material visade vi vanligtvis mycket enkla exempel på bash-skript som bestod av bokstavligen några rader. Nästa gång ska vi titta på något större.

Kära läsare! Använder du reguljära uttryck när du bearbetar text i kommandoradsskript?