Reguljära uttryck och kommandot grep. Använda Grep och reguljära uttryck för att hitta textmönster i Linux Egrep exempel på 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 att använda i skript kommandorad Linux.

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 åsikt 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

Implementering av reguljära uttryck i olika miljöer, såsom programmeringsspråk som Java, Perl och Python, 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 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.

Särskilda symboler

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/(print $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å beaktas. Låt oss se hur detta påverkar bearbetningen 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ågot mellan början och slutet av raden, och tack vare utropstecknet 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ända en prick i reguljära uttryck

Som framgår av utdata, motsvarar endast de två första raderna från filen mönstret, eftersom de innehåller sekvensen av tecken "st" som 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 väldigt praktiska när man söker efter ord som kan börja med både versaler och 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 vanligaste 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 de symboler som diskuterats ovan, men de tillåter dig att 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)"


Gruppera 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 adresser E-post, telefonnummer, och så vidare. Men det är 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 montera 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: ”I början av raden måste det finnas minst ett tecken från de som finns i den grupp som anges i hakparentes, och efter det borde det finnas 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?

Ett av de mest användbara och funktionsrika kommandona i Linux-terminalen är kommandot "grep". Grep är en akronym som står för "global regular expression print" (det vill säga "sök överallt efter strängar som matchar ett reguljärt uttryck och skriv ut dem"). Detta innebär att grep kan användas för att se om indata matchar specificerade mönster.

Detta till synes triviala program är mycket kraftfullt när det används på rätt sätt. Dess förmåga att sortera indata baserat på komplexa regler gör den till en populär länk i många kommandokedjor.

Den här handledningen tittar på några av grep-kommandots funktioner och går sedan vidare till att använda reguljära uttryck. Alla tekniker som beskrivs i den här guiden kan användas för att hantera en virtuell server.

Grunderna för användning

I sin enklaste form används grep för att hitta matchningar av bokstavsmönster i en textfil. Detta betyder att om grep ges ett sökord, kommer det att skriva ut varje rad i filen som innehåller det ordet.

Som ett exempel kan du använda grep för att hitta rader som innehåller ordet "GNU" i version 3 av GNU General Public License på ett Ubuntu-system.

cd /usr/share/common-licenses
grep "GNU" GPL-3
GNU GENERAL OFFENTLIG LICENS





13. Använd med GNU Affero General Public License.
under version 3 av GNU Affero General Public License till en singel
...
...

Det första argumentet, "GNU", är mönstret att söka efter, och det andra argumentet, "GPL-3", är indatafilen som ska hittas.

Som ett resultat kommer alla rader som innehåller textmönstret att matas ut. I några Linux-distributioner mönstret du letar efter kommer att markeras i utdataraderna.

Generella val

Som standard söker kommandot grep helt enkelt efter strikt specificerade mönster i inmatningsfilen och skriver ut raderna som det hittar. Men greps beteende kan ändras genom att lägga till några ytterligare flaggor.

Om du behöver ignorera sökparameterns skiftläge och söka efter varianter av både versaler och gemener av mönstret, kan du använda verktygen "-i" eller "--ignore-case".

Som ett exempel kan du använda grep för att söka i samma fil efter ordet "licens" skrivet med versaler, gemener eller blandade bokstäver.

grep -i "license" GPL-3
GNU GENERAL OFFENTLIG LICENS
i detta licensdokument, men det är inte tillåtet att ändra det.
GNU General Public License är en gratis copyleft-licens för
Licenserna för de flesta programvara och andra praktiska arbeten utformas
GNU General Public License är avsedd att garantera din frihet att
GNU General Public License för de flesta av vår programvara; det gäller också


"Denna licens" hänvisar till version 3 av GNU General Public License.
"Programmet" hänvisar till alla upphovsrättsskyddade verk som licensieras under detta
...
...

Som du kan se innehåller utgången "LICENS", "licens" och "Licens". Om det fanns en instans av "LiCeNsE" i filen, skulle den också matas ut.
Om du behöver hitta alla linjer som inte innehåller det angivna mönstret kan du använda flaggorna "-v" eller "--invert-match".

Som ett exempel kan du använda följande kommando för att söka i BSD-licensen efter alla rader som inte innehåller ordet "the":

grep -v "the" BSD
Alla rättigheter förbehållna.
Omfördelning och användning i källform och binär form, med eller utan
är uppfyllda:
kan användas för att rekommendera eller marknadsföra produkter som härrör från denna programvara
utan särskilt skriftligt tillstånd i förväg.
DENNA PROGRAM TILLHANDAHÅLLS AV REGENTERNA OCH BIDRAGARE "I BEFINTLIGT SKICK"""
NÅGRA UTTRYCKTA ELLER UNDERFÖRSTÅDDA GARANTIER, INKLUSIVE, MEN INTE BEGRÄNSADE TILL,
...
...

Som du kan se matades de två sista raderna ut som att de inte innehöll ordet "the" eftersom kommandot "ignore case" inte användes.

Det är alltid bra att veta radnumren där matchningarna hittades. De kan hittas med flaggorna "-n" eller "--line-number".

Om du använder denna flagga i föregående exempel kommer följande resultat att visas:

grep -vn "the" BSD
2: Alla rättigheter reserverade.
3:
4:Omfördelning och användning i källform och binär form, med eller utan
6:är uppfyllda:
13: kan användas för att rekommendera eller marknadsföra produkter som härrör från denna programvara
14: utan särskilt skriftligt tillstånd.
15:
16:DEN HÄR PROGRAMVARAN TILLHANDAHÅLLS AV REGENTERNA OCH BIDRAGARE "I BEFINTLIGT SKICK"""
17: EVENTUELLA UTTRYCKLIGA ELLER UNDERFÖRSTÅDDA GARANTIER, INKLUSIVE, MEN INTE BEGRÄNSADE TILL,
...
...

Du kan nu hänvisa till radnumret när du behöver göra ändringar på varje rad som inte innehåller "the".

Vanliga uttryck

Som nämnts i inledningen står grep för "global regular expression print". Ett reguljärt uttryck är en textsträng som beskriver ett specifikt sökmönster.

Olika applikationer och programmeringsspråk använder reguljära uttryck lite olika. Denna handledning täcker bara en liten del av sätt att beskriva mönster för Grep.

Bokstäver matchar

I exemplen ovan på att söka efter orden "GNU" och "the", letade man efter mycket enkla reguljära uttryck som exakt matchade teckensträngen "GNU" och "the".

Det är mer korrekt att tänka på dem som matchningar av teckensträngar snarare än som matchningar av ord. När du väl blir bekant med mer komplexa mönster kommer denna distinktion att bli mer betydelsefull.

Mönster som exakt matchar givna tecken kallas "bokstavsmönster" eftersom de matchar mönstret bokstav för bokstav, tecken för tecken.

Alla alfabetiska och numeriska tecken (och vissa andra tecken) matchar bokstavligen om de inte har modifierats av andra uttrycksmekanismer.

Ankarmatcher

Ankare är specialtecken som indikerar platsen i en sträng för den önskade matchningen.

Du kan till exempel ange att sökningen bara behöver rader som innehåller ordet "GNU" i början. För att göra detta måste du använda ankaret "^" före bokstavssträngen.

Detta exempel skriver bara ut rader som innehåller ordet "GNU" i början.

grep "^GNU" GPL-3
GNU General Public License för de flesta av vår programvara; det gäller också
GNU General Public License, du kan välja vilken version som helst som någonsin publicerats

På samma sätt kan ankaret "$" användas efter en bokstavlig sträng för att indikera att matchningen endast är giltig om teckensträngen som söks på är i slutet av textsträngen.

Följande reguljära uttryck skriver bara ut de rader som innehåller "och" i slutet:

grep "och$" GPL-3
att det inte finns någon garanti för denna gratis programvara. För både användare" och
De exakta villkoren för kopiering, distribution och


alternativ tillåts endast ibland och icke-kommersiellt, och
nätverk kan nekas när själva ändringen materiellt och
negativt påverkar driften av nätverket eller bryter mot reglerna och
provisoriskt, om inte och tills upphovsrättsinnehavaren uttryckligen och
får en licens från de ursprungliga licensgivarna för att köra, ändra och
göra, använda, sälja, erbjuda till försäljning, importera och på annat sätt driva, modifiera och

Matcha vilken karaktär som helst

Punkten (.) används i reguljära uttryck för att indikera att vilket tecken som helst kan visas på den angivna platsen.

Om du till exempel vill hitta matchningar som innehåller två tecken och sedan sekvensen "cept", skulle du använda följande mönster:

grep "..cept" GPL-3
användning, vilket är just där det är mest oacceptabelt. Därför, vi
intrång enligt tillämplig upphovsrättslagstiftning, förutom att verkställa den på en
talar om för användaren att det inte finns någon garanti för arbetet (förutom till

form av en separat skriftlig licens, eller anges som undantag;
Du får inte sprida eller modifiera ett täckt verk annat än uttryckligen
9. Godkännande krävs inte för att ha kopior.
...
...

Som du kan se inkluderar resultaten orden "acceptera" och "utom", såväl som varianter av dessa ord. Mönstret skulle också matcha sekvensen "z2cept" om det fanns i texten.

Uttryck inom parentes

Genom att placera en grupp tecken inom hakparenteser ("") kan du indikera att vilket som helst av tecknen inom hakparenteserna kan visas på den positionen.

Det betyder att om du behöver hitta strängar som innehåller "för" eller "två", kan du kort ange dessa varianter med hjälp av följande mönster:

grep "till" GPL-3
dina program också.

Utvecklare som använder GNU GPL skyddar dina rättigheter med två steg:
ett datornätverk, utan överföring av en kopia, förmedlar inte.

Motsvarande källa från en nätverksserver utan kostnad.
...
...

Som du kan se hittades båda varianterna i filen.

Att sätta tecken inom parentes ger också flera användbara funktioner. Du kan indikera att allt utom tecknen inom parentes matchar mönstret genom att starta listan med tecken inom parentes med tecknet "^".

Det här exemplet använder mönstret ".ode", som inte får matcha "kod"-sekvensen.

grep "[^c]ode" GPL-3
1. Källkod.
modell, för att ge alla som har objektkoden antingen (1) a
det enda betydande användningssättet för produkten.
märk så här när den startar i ett interaktivt läge:

Det är värt att notera att den andra radens utdata innehåller ordet "kod". Detta är inte ett regex- eller grep-fel.

Den här raden skrevs snarare ut eftersom den också innehåller den mönstermatchande sekvensen "läge" som finns i ordet "modell". Det vill säga att snöret trycktes för att det matchade mönstret.

En annan användbar funktion med parenteser är möjligheten att specificera ett antal tecken istället för att behöva skriva varje tecken individuellt.

Det betyder att om du behöver hitta varje rad som börjar med en stor bokstav kan du använda följande mönster:

grep "^" GPL-3
GNU General Public License för de flesta av vår programvara; det gäller också

Licens. Varje licenstagare tilltalas som "du". "Licenser" och


Systembibliotek, eller allmänna verktyg eller allmänt tillgängliga gratis
Källa.

...
...

På grund av vissa inneboende sorteringsproblem är det bättre att använda POSIX-teckenklasser för mer exakta resultat istället för teckenintervallet som används i exemplet ovan.
Det finns många teckenklasser som inte tas upp i denna handbok; till exempel, för att utföra samma procedur som i exemplet ovan, kan du använda teckenklassen "[:upper:]" inom parentes.

grep "^[[:upper:]]" GPL-3
GNU General Public License för de flesta av vår programvara; det gäller också
Stater bör inte tillåta patent att begränsa utveckling och användning av
Licens. Varje licenstagare tilltalas som "du". "Licenser" och
Komponent, och (b) tjänar endast till att möjliggöra användning av arbetet med det
Huvudkomponent, eller för att implementera ett standardgränssnitt för vilket en
Systembibliotek, eller allmänna verktyg eller allmänt tillgängliga gratis
Källa.
Användarprodukten överförs till mottagaren för all framtid eller för en
...
...

Upprepa mönstret (0 eller fler gånger)

En av de vanligaste metatecken är "*"-symbolen, som betyder "upprepa föregående tecken eller uttryck 0 eller fler gånger."

Om du till exempel vill hitta varje rad med öppnande eller avslutande parenteser som bara innehåller bokstäver och enstaka mellanslag mellan dem, kan du använda följande uttryck:

grep "(*)" GPL-3

distribution (med eller utan ändring), tillgängliggörande för
än verket som helhet, som (a) ingår i den normala formen av
Komponent, och (b) tjänar endast till att möjliggöra användning av arbetet med det
(om någon) som det körbara verket körs på, eller en kompilator som används för
(inklusive ett fysiskt distributionsmedium), tillsammans med
(inklusive ett fysiskt distributionsmedium), åtföljd av en
plats (gratis eller mot en avgift), och erbjuda likvärdig tillgång till
...
...

Hur man undviker metatecken

Ibland kan du behöva leta efter en bokstavlig period eller en bokstavlig öppen parentes. Eftersom dessa tecken har en specifik betydelse i reguljära uttryck, måste du "fly" dem genom att tala om för grep att deras speciella betydelse inte behövs i det här fallet.

Dessa tecken kan escapes genom att använda ett omvänt snedstreck (\) före tecknet, vilket vanligtvis har speciell betydelse.

Om du till exempel behöver hitta en sträng som börjar med stor bokstav och slutar med punkt kan du använda uttrycket nedan. Omvänt snedstreck före den sista punkten talar om för kommandot att "escape" det, så att den sista punkten representerar en bokstavlig punkt och inte har någon betydelse för "något tecken":

grep "^.*\.$" GPL-3
Källa.
Licens genom att göra undantag från ett eller flera av dess villkor.
Licens skulle vara att helt avstå från att förmedla programmet.
ALL NÖDVÄNDIG SERVICE, REPARATION ELLER KORREKTION.
SÅDANA SKADOR.
Lägg även till information om hur du kontaktar dig via e-post och papperspost.

Avancerade reguljära uttryck

Grep-kommandot kan också användas med ett utökat reguljärt uttrycksspråk genom att använda flaggan -E eller genom att anropa kommandot egrep istället för grep.

Dessa kommandon öppnar möjligheterna för "utökade reguljära uttryck". Utökade reguljära uttryck inkluderar alla grundläggande metatecken, såväl som ytterligare metatecken för att uttrycka mer komplexa matchningar.

Gruppering

En av de enklaste och mest användbara funktionerna som utökade reguljära uttryck ger är möjligheten att gruppera uttryck och använda dem som en enda enhet.

Parenteser används för att gruppera uttryck. Om du behöver använda parenteser utanför utökade reguljära uttryck kan de "escapes" med ett omvänt snedstreck

grep "\(gruppering\)" file.txt
grep -E "(gruppering)" file.txt
egrep "(gruppering)" file.txt

Ovanstående uttryck är likvärdiga.

Alternering

Precis som hakparenteser anger olika möjliga matchningar för ett enstaka tecken, låter interfoliering dig ange alternativa matchningar för teckensträngar eller uppsättningar uttryck.

Den vertikala strecksymbolen "|" används för att indikera växling. Alternering används ofta i gruppering för att indikera att ett av två eller flera möjliga alternativ ska betraktas som en matchning.

I det här exemplet måste du leta efter "GPL" eller "General Public License":

grep -E "(GPL|General Public License)" GPL-3
GNU General Public License är en gratis copyleft-licens för
GNU General Public License är avsedd att garantera din frihet att
GNU General Public License för de flesta av vår programvara; det gäller också
pris. Våra allmänna offentliga licenser är utformade för att säkerställa att du
Utvecklare som använder GNU GPL skyddar dina rättigheter med två steg:
För skyddet av utvecklarna och författarna förklarar GPL tydligt
författares skull kräver GPL att modifierade versioner markeras som
har utformat den här versionen av GPL för att förbjuda dessa
...
...

Alternering kan användas för att välja mellan två eller flera alternativ; För att göra detta måste du ange de återstående alternativen i urvalsgruppen, separera var och en med den vertikala strecksymbolen "|".

Kvantifierare

I utökade reguljära uttryck finns det metatecken som anger hur ofta ett tecken upprepas, ungefär som metateckenet "*" indikerar att det föregående tecknet eller strängen med tecken matchar 0 eller fler gånger.

För att matcha ett tecken 0 eller fler gånger kan du använda tecknet "?". Det kommer att göra den tidigare karaktären eller serien av tecken i huvudsak valfri.

I det här exemplet, genom att infoga sekvensen "copy" i den valfria gruppen, visas matchningarna "copyright" och "right":

grep -E "(copy)?right" GPL-3
Copyright (C) 2007 Free Software Foundation, Inc.
För att skydda dina rättigheter måste vi förhindra andra från att neka dig
dessa rättigheter eller ber dig att avstå från rättigheterna. Därför har du
känner till sina rättigheter.
Utvecklare som använder GNU GPL skyddar dina rättigheter med två steg:
(1) hävda upphovsrätten till programvaran och (2) erbjuda dig denna licens
"Upphovsrätt" betyder också upphovsrättsliknande lagar som gäller andra typer av
...
...

Tecknet "+" matchar uttryck 1 eller flera gånger. Det fungerar nästan som "*"-symbolen, men när du använder "+" måste uttrycket matcha minst 1 gång.

Följande uttryck matchar strängen "free" plus 1 eller fler tecken som inte är blanksteg:

grep -E "free[^[:mellanslag:]]+" GPL-3
GNU General Public License är en gratis copyleft-licens för
att ta bort din frihet att dela och förändra verken. Däremot
GNU General Public License är avsedd att garantera din frihet att
När vi talar om fri programvara syftar vi på frihet, inte
ha friheten att distribuera kopior av fri programvara (och ta betalt för

friheter som du fått. Du måste se till att de också tar emot
skydda användarnas frihet att ändra programvaran. Den systematiska
av GPL, efter behov för att skydda användarnas frihet.
patent kan inte användas för att göra programmet icke-fritt.

Antal upprepade matcher

Om du behöver ange hur många gånger matchningar ska upprepas kan du använda hängslen (“( )”). Dessa symboler används för att indikera det exakta antalet, intervallet och övre och nedre gränser för antalet matchningar av ett uttryck.

Om du behöver hitta alla rader som innehåller en kombination av tre vokaler kan du använda följande uttryck:

grep -E "(3)" GPL-3
ändrats, så att deras problem inte felaktigt kommer att hänföras till
författare till tidigare versioner.
ta emot det, i vilket medium som helst, förutsatt att du på ett iögonfallande sätt och
ge enligt föregående stycke, plus en rätt till besittning av
täckt arbete för att samtidigt uppfylla dina skyldigheter enligt detta
Om du behöver hitta alla ord som består av 16-20 tecken, använd följande uttryck:
grep -E "[[:alpha:]](16,20)" GPL-3
vissa skyldigheter om du distribuerar kopior av programvaran, eller om
du ändrar det: ansvar att respektera andras frihet.
c) Förbjuda felaktig framställning av materialets ursprung, eller

Slutsatser

I många fall är kommandot grep användbart för att hitta mönster i filer eller i en hierarki filsystem. Det sparar mycket tid, så det är värt att bekanta dig med dess parametrar och syntax.

Reguljära uttryck är ännu mer mångsidiga och kan användas i många populära program. Till exempel många textredigerare använda reguljära uttryck för att söka och ersätta text.

Dessutom använder avancerade programmeringsspråk reguljära uttryck för att utföra procedurer på specifika datastycken. Att veta hur man arbetar med reguljära uttryck är praktiskt när man löser vanliga datorrelaterade problem.

Taggar: ,

Ett av de mest användbara och funktionsrika kommandona i Linux-terminalen är kommandot "grep". Namnet är en akronym för den engelska frasen "sök globalt efter linjer som matchar det reguljära uttrycket och skriv ut dem" (sök överallt efter linjer som matchar det reguljära uttrycket och skriv ut dem). Kommandot "grep" skannar indataströmmen rad för rad, letar efter matchningar och utdata (filtrerar) endast de rader som innehåller text som matchar det givna mönstret - vanligt uttryck.

Reguljära uttryck är ett speciellt formellt språk för att söka och manipulera delsträngar i text, baserat på användningen av metatecken. Nu har nästan alla moderna programmeringsspråk inbyggt stöd för reguljära uttryck för textbehandling, men historiskt har UNIX-världen och i synnerhet idéerna inbäddade i kommandona "grep", "sed" etc. bidragit mycket. till populariseringen av detta tillvägagångssätt Filosofin "allt är en fil" » genomsyrar UNIX fullständigt och behärskning av verktyg för att arbeta med textfiler är en av de färdigheter som krävs för varje Linux-användare.

PROV

GIST | En enkel sökning efter alla rader som innehåller texten "Adams". När vi formaterar detta och efterföljande exempel kommer vi att följa följande ordning: kommandoradsparametrar överst, standardströmmar längst ner, stdin-ingång till vänster och stdout-utgång till höger.

Kommandot "grep" har ett imponerande antal alternativ som du kan ange när du kör det. Du kan göra många användbara saker med dessa alternativ, och du behöver inte ens vara väl insatt i syntax för reguljära uttryck.

ALTERNATIV

Låt oss börja med det faktum att "grep" inte bara kan filtrera standardindata stdin, utan också söka igenom filer. Som standard kommer grep bara att söka efter filer i den aktuella katalogen, men med det mycket användbara alternativet --recursive kan du säga till grep att söka rekursivt från en given katalog.

GIST | Som standard är kommandot grep skiftlägeskänsligt. Följande exempel visar hur du kan söka utan att det är skiftlägeskänsligt, till exempel är "Adams" och "adams" samma sak:

Ignorera "adams"

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

GIST | Sökningen är den motsatta (ibland säger de inverterad sökning), det vill säga alla rader kommer att visas utom de som har en förekomst av det angivna mönstret:

Invertera-match "Adams"

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

GIST | Alternativ kan och bör naturligtvis kombineras med varandra. Till exempel, en omvänd sökning med visning av serienumren på rader med förekomster:

Radnummer --invertera-matcha "Adams"

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

GIST | Färg. Ibland är det bekvämt när ordet vi letar efter är markerat i färg. Allt detta finns redan i "grep", allt som återstår är att inkludera:

Radnummer --color=alltid "Adams"

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

GIST | Vi vill välja alla fel från loggfilen, men vi vet att nästa rad efter felet kan innehålla användbar information, då är det bekvämt att visa flera rader från sammanhanget. Som standard kommer grep bara att skriva ut raden där matchningen hittades, men det finns flera alternativ för att få grep att skriva ut mer. För att mata ut flera rader (i vårt fall två) efter en post:

Färg=alltid -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 Mad Jefferson, 1801-189, 1801-189, 1801-189, 1801-189

GIST | Likaså för ytterligare utmatning av flera rader före posten:

Färg=alltid -B2 "James"

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 Mad Jefferson, 1801-18 Monroe, 1801-18 1817-1825

GIST | Men oftast behöver du visa ett symmetriskt sammanhang, det finns en ännu kortare notation för detta. Låt oss skriva ut två rader både ovanför och under posten:

Färg=alltid -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-1829-178 Martin Van Buren, 1829-1817-18 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 | När du söker efter qwe kommer "grep" som standard också att mata ut qwe123, 345qwerty och liknande kombinationer. Låt oss bara hitta de raderna som stänger av hela ordet:

Word-regexp --color=alltid "John"

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

GIST | Och slutligen, om du bara vill veta antalet rader med matchningar av ett enda nummer, men inte visa något annat:

Räkna --färg=alltid "John"

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

Det är värt att notera att de flesta alternativ har en motsvarighet, till exempel kan --ignore-case reduceras till den kortare formen -i, etc.

GRUNDLÄGGANDE VANLIGA UTTRYCK

Alla reguljära uttryck består av två typer av tecken: standardtexttecken kallas bokstavliga ord, och specialtecken kallas metakaraktärer. I de tidigare exemplen utfördes sökningen med hjälp av bokstaver (exakt matchning av bokstäver), men det som följer kommer att bli mycket mer intressant. Välkommen till en värld av reguljära uttryck!

Caret ^ och dollartecken $ har speciella betydelser i ett reguljärt uttryck. De kallas "ankare". Ankare är specialtecken som indikerar platsen i en sträng för den önskade matchningen. När sökningen når ett ankare kontrollerar den om det finns en matchning, och i så fall fortsätter den att följa mönstret. utan att tillföra något till resultatet.

GIST | Caretankaret används för att indikera att det reguljära uttrycket måste testas från början av raden:

Färg=alltid "^J"

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

GIST | På samma sätt bör dollarankaret användas i slutet av mönstret för att indikera att matchningen endast är giltig om teckensträngen som söks på är i slutet av textsträngen och inte annars:

Färg=alltid "9$"

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

GIST | Vilken karaktär som helst. Punkttecknet används i reguljära uttryck för att indikera att absolut alla tecken kan visas på den angivna platsen:

Färg=alltid "0.$"

GIST | Avskärmning. Om du behöver hitta exakt pricksymbolen hjälper det att fly. Ett flykttecken (vanligtvis ett omvänt snedstreck) som föregår ett tecken som en prick förvandlar metateckenet till en bokstavlig:

Färg=alltid "\."

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

GIST | Karaktärsklasser. Reguljära uttryck kan använda intervall och teckenklasser. För att göra detta används hakparenteser när du skapar mallen. Genom att placera en grupp tecken (inklusive tecken som annars skulle tolkas som metatecken) inom hakparenteser, kan du indikera att vilket som helst av tecknen inom parentes kan visas på den positionen:

Färg=alltid "0"

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

GIST | Räckvidd. Dessa är två tecken åtskilda av ett bindestreck, till exempel 0-9 (decimala siffror) eller 0-9a-fA-F (hexadecimala siffror):

Färg=alltid ""

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

GIST | Negation. Om det första tecknet i uttrycket inom hakparenteser är en rad, tas de återstående tecknen som en uppsättning tecken som inte ska finnas på den givna positionen för det reguljära uttrycket:

Färg=alltid "[^7]$"

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

GIST | POSIX teckenklasser. Det finns en viss uppsättning förberedda teckenklasser som du kan använda i reguljära uttryck. Det finns ungefär ett dussin av dem, titta bara snabbt igenom manualen för att förstå syftet med var och en. Låt oss till exempel bara filtrera hexadecimala siffror:

Färg=alltid "^[[:xdigit:]]*$"

4,2 42 42abc 42 42abc

GIST | Upprepa (0 eller fler gånger). En av de vanligaste metatecken är asterisksymbolen, som betyder "upprepa föregående tecken eller uttryck noll eller fler gånger":

Färg=alltid "^*$"

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

Det finns grundläggande reguljära uttryck BRE (grundläggande reguljära uttryck) och utökade reguljära uttryck ERE (extended reguljära uttryck). Följande metatecken känns igen i BRE: ^$. * och alla andra tecken behandlas som bokstavliga. Har följande metatecken lagts till i ERE () ( ) ? + | och relaterade funktioner. Tja, för att fullständigt förvirra alla, kom de på den här saken i "grep" - tecknen () ( ) i BRE behandlas som metatecken om de undkommer med ett snedstreck, medan de i ERE placerar ett snedstreck framför alla metakaraktärer leder till att de behandlas som bokstavliga.

AVANCERADE VANLIGA UTTRYCK

GIST | Åtskiljande. Precis som hakparenteser anger olika möjliga matchningar för ett enskilt tecken, låter en disjunktion dig ange alternativa matchningar för teckensträngar eller uttryck. Den vertikala strecksymbolen används för att indikera disjunktion:

Extended-regexp --color=alltid "George|John"

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

GIST | Matcha noll eller en gång. I utökade reguljära uttryck finns det flera ytterligare metatecken som anger hur ofta ett tecken eller uttryck upprepas (liknande hur asteriskens metatecken indikerar matchningar av 0 eller fler gånger). En sådan metakaraktär är frågetecknet, vilket gör det föregående tecknet eller uttrycket i huvudsak valfritt:

Extended-regexp --color=alltid "^(Andrew)?John"

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

GIST | Matcha en eller flera gånger. För detta ändamål tillhandahålls en metatecken i form av ett plustecken. Det fungerar nästan som en asterisksymbol, förutom att uttrycket måste matcha minst en gång:

Extended-regexp --color=alltid "^[[:alpha:] ]+$"

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

GIST | Matcha det angivna antalet gånger. Du kan använda lockiga hängslen för detta. Dessa metatecken används för att indikera det exakta antalet, intervallet och övre och nedre gränsen för antalet matchningar av ett uttryck:

Extended-regexp --color=alltid "(1,3)\.(1,3)\.(1,3)\.(1,3)"

42 127.0.0.1 127.0.0.1

grep-kommandot är så användbart, funktionsrikt och lätt att använda att när du väl vet det, kan du inte föreställa dig att arbeta utan det.

Bakgrund och källa: Inte alla som måste använda reguljära uttryck förstår helt hur de fungerar eller hur man skapar dem. Jag tillhörde också denna grupp - jag letade efter exempel på reguljära uttryck som lämpade sig för mina uppgifter, försökte korrigera dem vid behov. Allt förändrades radikalt för mig efter att ha läst boken. Linux Command Line (Andra Internet Edition) författare William E. Shotts, Jr. Den anger principerna för hur reguljära uttryck fungerar så tydligt att jag efter att ha läst lärt mig att förstå dem, skapa reguljära uttryck av vilken komplexitet som helst och nu använda dem när det behövs. Detta material är en översättning av den del av kapitlet som ägnas åt reguljära uttryck. Detta material är avsett för absolut nybörjare som absolut inte har någon förståelse för hur reguljära uttryck fungerar, men som har en viss förståelse för hur reguljära uttryck fungerar. Jag hoppas att den här artikeln hjälper dig att göra samma genombrott som hjälpte mig. Om materialet som presenteras här inte innehåller något nytt för dig, försök att titta på artikeln "Reguljära uttryck och grep-kommandot", den beskriver grep-alternativ mer i detalj, såväl som ytterligare exempel.

Hur används reguljära uttryck?

Textdata spelar en viktig roll i alla Unix-liknande system som Linux. Texten är bland annat utdata av konsolprogram, konfigurationsfiler, rapporter m.m. Vanliga uttryckär (kanske) ett av de svåraste begreppen i att arbeta med text, eftersom de involverar hög nivå abstraktioner. Men tiden som ägnas åt att studera dem kommer mer än att löna sig. Om du vet hur man använder reguljära uttryck kan du göra fantastiska saker, även om deras fulla värde kanske inte är direkt uppenbart.

Den här artikeln kommer att titta på hur du använder reguljära uttryck tillsammans med kommandot grep. Men deras användning är inte begränsad till detta: reguljära uttryck stöds av andra Linux-kommandon, många programmeringsspråk, används i konfigurationen (till exempel i mod_rewrite-regelinställningarna i Apache), liksom vissa program med grafiskt gränssnitt låter dig ställa in regler för sök/kopiera/radera med stöd för reguljära uttryck. Även i det populära kontorsprogrammet Microsoft Word kan du använda reguljära uttryck och jokertecken för att hitta och ersätta text.

Vad är reguljära uttryck?

Tala på ett enkelt språk, är ett reguljärt uttryck en konvention, en symbolisk notation av ett mönster som söks efter i texten. Reguljära uttryck stöds av många kommandoradsverktyg och de flesta programmeringsspråk och används för att lösa textmanipuleringsproblem. Men som om deras komplexitet inte är tillräckligt för oss, skapas inte alla reguljära uttryck lika. De varierar något från verktyg till verktyg och från programmeringsspråk till språk. För vår diskussion kommer vi att begränsa oss till de reguljära uttryck som beskrivs i POSIX-standarden (som kommer att täcka de flesta kommandoradsverktyg), i motsats till många programmeringsspråk (främst Perl), som använder lite större och rikare uppsättningar av notationer .

grep

Huvudprogrammet vi kommer att använda för reguljära uttryck är vår gamla vän, . Namnet "grep" kommer faktiskt från frasen "global regular expression print", så vi kan se att grep har något med reguljära uttryck att göra. I huvudsak söker grep i textfiler efter text som matchar ett angivet reguljärt uttryck och skriver ut till standardutdata vilken rad som helst som innehåller en matchning.

grep kan söka efter text mottagen i standardinmatning, till exempel:

ls /usr/bin | grep zip

Detta kommando kommer att lista filer i katalogen /usr/bin vars namn innehåller understrängen "zip".

grep-programmet kan söka efter text i filer.

Syntax för allmän användning:

Grep [alternativ] regex [fil...]

  • regexär ett reguljärt uttryck.
  • [fil…]- en eller flera filer som kommer att genomsökas med ett reguljärt uttryck.

[alternativ] och [fil...] ​​kan saknas.

Lista över de mest använda grep-alternativen:

Alternativ Beskrivning
-jag Ignorera fall. Gör inte skillnad på stora och små tecken. Du kan också ställa in alternativet --ignorera fall.
-v Invertera Match. Normalt kommer grep att skriva ut raderna som innehåller matchningen. Det här alternativet gör att grep skriver ut varje rad som inte innehåller en matchning. Du kan också använda --invertera-match.
-c Skriv ut antalet matchningar (eller felmatchningar om alternativet är angivet -v) istället för själva linjerna. Du kan också ange alternativet --räkna.
-l Skriv ut namnet på varje fil som innehåller matchningen istället för själva strängarna. Kan specificeras med alternativet --filer-med-matchningar.
-L Som ett alternativ -l, men skriver bara ut filnamn som inte innehåller matchningar. Ett annat alternativnamn --filer-utan matchning.
-n Lägga till ett radnummer i filen i början av varje matchad rad. Ett annat alternativnamn --linje nummer.
-h För att söka i flera filer, dämpa filnamnsutmatningen. Du kan också ange alternativet -- inget filnamn.

För att utforska grep mer fullständigt, låt oss skapa några textfiler att söka efter:

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

Vi kan göra en enkel sökning genom vår lista med filer så här:

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

I det här exemplet söker grep alla listade filer efter strängen bzip och hittar två matchningar, båda i filen dirlist-bin.txt. Om vi ​​bara är intresserade av listan över filer som innehåller matchningarna, och inte de matchande strängarna i sig, kan vi ange alternativet -l:

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

Omvänt, om vi bara ville se en lista över filer som inte innehöll matchningar, kunde vi göra så här:

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

Om det inte finns någon utdata betyder det att inga filer som uppfyller villkoren hittades.

Metatecken och bokstavliga tecken

Även om det kanske inte verkar självklart, använder våra grep-sökningar alltid reguljära uttryck, om än väldigt enkla. Det reguljära uttrycket "bzip" betyder att en matchning kommer att inträffa (dvs raden kommer att betraktas som en matchning) endast om raden i filen innehåller minst fyra tecken och att tecknen "b", "z" finns någonstans på raden , "i" och "p" är i den ordningen, utan några andra tecken emellan. Tecknen i "bzip"-strängen är bokstavliga ord, dvs. bokstavliga symboler, eftersom de motsvarar dem själva. Förutom bokstavliga ord kan reguljära uttryck även inkludera metakaraktärer, som används för att specificera mer komplexa matchningar. Reguljära uttrycksmetakaraktärer består av följande:

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

Alla andra karaktärer anses vara bokstavliga. Omvänt snedstreck kan ha olika betydelser. Den används i flera fall för att skapa metasekvenser, och tillåter också att metakaraktärer undkomms och behandlas inte som metatecken, utan som bokstavliga.

Notera: som vi kan se är många reguljära uttrycksmetakaraktärer också skalbetydande karaktärer (utför expansion). När du anger ett reguljärt uttryck som innehåller kommandoradsmetatecken är det absolut nödvändigt att det omges av citattecken, annars tolkar skalet dem på sitt eget sätt och bryter ditt kommando.

Vilken karaktär som helst

Den första metakaraktären som vi kommer att börja bekanta oss med är pricksymbol, vilket betyder "vilken karaktär som helst". Om vi ​​inkluderar det i ett reguljärt uttryck, kommer det att matcha vilket tecken som helst för den teckenpositionen. Exempel:

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

Vi letade efter valfri sträng i våra filer som matchade det reguljära uttrycket ".zip". Det finns ett par intressanta punkter att notera om resultaten. Observera att zip-programmet inte hittades. Detta beror på att inkludering av punktmetatecken i vårt reguljära uttryck ökade längden som krävs för en matchning till fyra tecken, och eftersom namnet "zip" bara innehåller tre matchar det inte. Dessutom, om någon av filerna i våra listor innehöll filtillägget .zip, skulle de också anses vara kvalificerade, eftersom punkttecknet i filtillägget också kvalificerar sig för villkoret "alla tecken".

Ankare

Caret symbol ( ^ ) och dollartecken ( $ ) beaktas i reguljära uttryck ankare. Det betyder att de bara orsakar en matchning om det reguljära uttrycket hittas i början av strängen ( ^ ) eller i slutet av raden ( $ ):

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

Här sökte vi i fillistorna efter strängen "zip" som finns i början av raden, i slutet av raden, och även på en rad där den skulle vara både i början och slutet (dvs hela raden skulle bara innehålla "zip"). Observera att det reguljära uttrycket " ^$ " (början och slutet med ingenting mellan) kommer att matcha tomma rader.

En kort utvikning: en korsordsassistent

Även med vår nuvarande begränsade kunskap om reguljära uttryck kan vi fortfarande göra något användbart.

Om du någonsin har gjort korsord, har du varit tvungen att lösa problem som "vad är fembokstavsordet där den tredje bokstaven är ett 'j' och den sista bokstaven är ett 'r' som betyder...". Den här frågan kan få dig att tänka. Visste du att i Linux-system har du en ordbok? Och han är. Titta i katalogen /usr/share/dict, du kan hitta en eller flera ordböcker där. Ordböckerna som publiceras där är helt enkelt långa listor med ord, en per rad, ordnade i alfabetisk ordning. På mitt system innehåller ordboksfilen 99171 ord. För att söka efter möjliga svar på ovanstående korsordsfråga kan vi göra så här:

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

Med detta reguljära uttryck kan vi hitta alla ord i vår ordboksfil som är fem bokstäver långa, har ett "j" i tredje positionen och ett "r" i sista positionen.

I exemplet användes en engelsk ordboksfil eftersom den finns på systemet som standard. Efter att tidigare ha laddat ner lämplig ordbok kan du göra liknande sökningar med ord på kyrilliska eller andra tecken.

Uttryck för parentes och karaktärsklasser

Förutom att matcha vilket tecken som helst på en given position i vårt reguljära uttryck använder vi också uttryck inom hakparenteser, kan vi ställa in en matchning till ett enskilt tecken från den angivna teckenuppsättningen. Med parentesuttryck kan vi ange en uppsättning tecken som ska matcha (inklusive tecken som annars skulle tolkas som metatecken). I det här exemplet använder du en uppsättning av två tecken:

Grep -h "zip" dirlist*.txt bzip2 bzip2recover gzip

vi hittar alla rader som innehåller strängarna "bzip" eller "gzip".

Uppsättningen kan innehålla valfritt antal tecken, och metatecken förlorar sin speciella betydelse när de placeras inom hakparenteser. Det finns dock två fall där metatecken som används inom hakparenteser har olika betydelser. Den första är vagnen ( ^ ), som används för att indikera negation; den andra är ett streck ( - ), som används för att ange ett teckenintervall.

Negation

Om det första tecknet i uttrycket inom hakparenteser är en indikator ( ^ ), så tas de återstående tecknen som en uppsättning tecken som inte ska finnas på den givna teckenpositionen. Låt oss göra detta genom att ändra vårt tidigare exempel:

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

Med negation aktiverad får vi en lista över filer som innehåller strängen "zip" föregås av något annat tecken än "b" eller "g". Observera att zip inte hittades. En negerad teckenuppsättning kräver fortfarande ett tecken på den givna positionen, men tecknet får inte vara en medlem av den negerade teckenuppsättningen.

Caret-tecknet förnekas endast om det är det första tecknet i ett uttryck inom parentes; annars förlorar den sitt speciella syfte och blir en vanlig symbol från setet.

Traditionella teckenintervall

Om vi ​​ville konstruera ett reguljärt uttryck som skulle hitta varje fil i vår lista som börjar med en stor bokstav, kunde vi göra följande:

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

Poängen är att vi sätter alla 26 versaler i uttrycket inom hakparenteser. Men tanken på att skriva ut dem alla inspirerar inte entusiasm, så det finns ett annat sätt:

Grep -h "^" dirlist*.txt

Genom att använda ett intervall på tre tecken kan vi förkorta posten på 26 bokstäver. Du kan uttrycka alla teckenintervall på detta sätt, inklusive flera intervall samtidigt, till exempel detta uttryck, som matchar alla filnamn som börjar med bokstäver och siffror:

Grep -h "^" dirlist*.txt

I teckenintervall ser vi att bindestrecket behandlas på ett speciellt sätt, så hur kan vi inkludera bindestrecket i ett uttryck inom hakparenteser? Genom att göra det till det första tecknet i uttrycket. Låt oss titta på två exempel:

Grep -h "" dirlist*.txt

Detta kommer att matcha alla filnamn som innehåller en stor bokstav. Vart i:

Grep -h "[-AZ]" dirlist*.txt

kommer att matcha alla filnamn som innehåller ett bindestreck eller ett stort "A" eller ett stort "Z".

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 åsikt 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 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.

Särskilda symboler

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/(print $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å beaktas. 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ågot mellan början och slutet av raden, och tack vare utropstecknet 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ända en prick i reguljära uttryck

Som framgår av utdata, motsvarar endast de två första raderna från filen mönstret, eftersom de innehåller sekvensen av tecken "st" som 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 vanligaste 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 de symboler som diskuterats ovan, men de tillåter dig att 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)"


Gruppera 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. Men det är 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 montera 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?


Topp