Linux-kommandot grep fungerar som ett mångsidigt verktyg för att söka efter specifika textsträngar och mönster. Det kan användas för att extrahera rader som matchar från flera filer, samt bearbeta utdata från andra kommandon. Här går vi igenom hur du kan använda det effektivt.
Grep:s ursprung
Kommandot grep är välkänt inom Linux- och Unix-världen av flera anledningar. För det första är det ett otroligt praktiskt verktyg. För det andra kan det stora antalet alternativ kännas överväldigande. För det tredje sägs det att det skapades över en natt för att lösa ett akut behov, även om detta senare visat sig vara en överskattning.
Ken Thompson hade dragit ut funktionaliteten för reguljära uttryck från ed-editorn (som uttalas ”ee-dee”) och skapade ett enkelt program för eget bruk för att söka i textfiler. Hans chef på Bell Labs, Doug Mcilroy, kontaktade Thompson med ett problem som hans kollega, Lee McMahon, brottades med.
McMahon försökte fastställa författarna till Federalist Papers genom textanalys. Han behövde ett verktyg som kunde söka efter specifika fraser och strängar i textfiler. Thompson tillbringade ungefär en timme samma kväll med att göra sitt verktyg allmänt användbart, och döpte om det till grep. Namnet kommer från ed-kommandot g/re/p, som står för ”global regular expression print” (ungefär ”global sökning med reguljära uttryck”).
Du kan höra Thompson berätta om hur grep kom till i ett samtal med Brian Kernighan.
Grundläggande sökningar med grep
För att söka efter en specifik sträng i en fil, skriver du söktermen följt av filnamnet på kommandoraden:
Rader som matchar visas. I det här fallet är det en enda rad. Den matchande texten är markerad, vilket beror på att grep på de flesta distributioner har ett alias:
alias grep='grep --colour=auto'
Låt oss undersöka fall där flera rader matchar. Vi letar efter ordet ”Genomsnitt” i en programloggfil. Eftersom vi inte är säkra på om ordet skrivs med gemener i loggfilen använder vi alternativet -i (ignorera skiftläge):
grep -i Average geek-1.log
Varje rad som matchar visas, och den matchande texten är markerad i varje rad.
Vi kan visa de rader som *inte* matchar genom att använda alternativet -v (invertera matchning).
grep -v Mem geek-1.log
Ingen text är markerad eftersom dessa är rader som *inte* matchar.
Vi kan få grep att vara helt tyst. Resultatet skickas till skalet som ett returvärde från grep. Ett resultat på noll betyder att strängen hittades och ett resultat på ett betyder att den inte hittades. Vi kan kontrollera returkoden med hjälp av de särskilda parametrarna $?:
grep -q average geek-1.log
echo $?
grep -q wdzwdz geek-1.log
echo $?
Rekursiva sökningar med grep
För att söka i kapslade kataloger och underkataloger använder du alternativet -r (rekursiv). Observera att du inte anger ett filnamn på kommandoraden utan en sökväg. Här söker vi i den aktuella katalogen ”.” och alla eventuella underkataloger:
grep -r -i memfree .
Utdata inkluderar katalogen och filnamnet för varje rad som matchar.
Vi kan få grep att följa symboliska länkar genom att använda alternativet -R (rekursiv dereference). I den här katalogen har vi en symbolisk länk som heter logs-folder. Den pekar på /home/dave/logs.
ls -l logs-folder
Låt oss upprepa vår senaste sökning med alternativet -R (rekursiv dereference):
grep -R -i memfree .
Den symboliska länken följs och katalogen som den pekar på genomsöks också av grep.
Söka efter hela ord
Som standard matchar grep en rad om söktermen finns någonstans på raden, inklusive inuti en annan sträng. Titta på det här exemplet. Vi söker efter ordet ”fri”.
grep -i free geek-1.log
Resultaten är rader som innehåller strängen ”fri”, men inte som separata ord. De är en del av strängen ”MemFree”.
För att tvinga grep att endast matcha separata ”ord”, använd alternativet -w (ord regexp).
grep -w -i free geek-1.log
echo $?
Den här gången finns det inga resultat, eftersom söktermen ”fri” inte förekommer som ett separat ord i filen.
Använda flera söktermer
Alternativet -E (extended regexp) låter dig söka efter flera ord. (Alternativet -E ersätter den utfasade egrep-versionen av grep.)
Det här kommandot söker efter två söktermer, ”genomsnittlig” och ”memfree”.
grep -E -w -i "average|memfree" geek-1.log
Alla matchande rader för respektive sökterm visas.
Du kan också söka efter flera termer som inte nödvändigtvis är hela ord, men de kan också vara hela ord.
Alternativet -e (mönster) låter dig använda flera sökord på kommandoraden. Vi använder funktionen för reguljära uttrycksparenteser för att skapa ett sökmönster. Det säger åt grep att matcha något av tecknen inom parentes ”[ ]”. Detta innebär att grep matchar antingen ”kB” eller ”KB” under sökningen.
Båda strängarna matchas och vissa rader innehåller faktiskt båda strängarna.
Matcha rader exakt
Alternativet -x (line regexp) matchar endast rader där hela raden matchar söktermen. Låt oss söka efter en datum- och tidsstämpel som vi vet visas endast en gång i loggfilen:
grep -x "20-Jan--06 15:24:35" geek-1.log
Den enskilda matchande raden hittas och visas.
Motsatsen till detta är att visa rader som *inte* matchar. Detta kan vara användbart när man granskar konfigurationsfiler. Kommentarer är bra, men ibland kan det vara svårt att se de faktiska inställningarna bland alla kommentarer. Här är filen /etc/sudoers:
Vi kan effektivt filtrera bort kommentarsraderna på följande sätt:
sudo grep -v "https://www.wdzwdz.com/496056/how-to-use-the-grep-command-on-linux/#" /etc/sudoers
Det är betydligt lättare att analysera.
Visa endast matchande text
Ibland vill man inte se hela den matchande raden utan bara den matchande texten. Alternativet -o (endast matchande) gör just det.
grep -o MemFree geek-1.log
Visningen är reducerad till att endast visa texten som matchar söktermen i stället för hela den matchande raden.
Räkna med grep
Grep är inte bara bra för att hitta text, utan kan också ge numerisk information. Vi kan få grep att räkna åt oss på olika sätt. Om vi vill veta hur många gånger en sökterm förekommer i en fil kan vi använda alternativet -c (count).
grep -c average geek-1.log
Grep rapporterar att söktermen förekommer 240 gånger i den här filen.
Du kan få grep att visa radnumret för varje matchande rad genom att använda alternativet -n (radnummer).
grep -n Jan geek-1.log
Radnumret för varje matchande rad visas i början av raden.
För att minska antalet resultat som visas använder du alternativet -m (maxantal). Vi begränsar utdata till fem matchande rader:
grep -m5 -n Jan geek-1.log
Lägga till kontext
Att kunna se några ytterligare rader – eventuellt icke-matchande rader – för varje matchande rad är ofta användbart. Det kan hjälpa dig att avgöra vilka av de matchade raderna som är de du är intresserad av.
För att visa några rader *efter* den matchande raden använder du alternativet -A (efter kontext). I det här exemplet begär vi tre rader:
grep -A 3 -x "20-Jan-06 15:24:35" geek-1.log
För att se några rader *före* den matchande raden använder du alternativet -B (sammanhang före).
grep -B 3 -x "20-Jan-06 15:24:35" geek-1.log
Och för att inkludera rader från både före och efter den matchande raden använder du alternativet -C (sammanhang).
grep -C 3 -x "20-Jan-06 15:24:35" geek-1.log
Visa matchande filer
För att se namnen på filerna som innehåller söktermen, använder du alternativet -l (filer med matchning). För att ta reda på vilka C-källkodsfiler som innehåller referenser till sl.h-huvudfilen kan du använda det här kommandot:
grep -l "sl.h" *.c
Filnamnen är listade, inte de matchande raderna.
Och naturligtvis kan vi söka efter filer som *inte* innehåller söktermen. Alternativet -L (filer utan matchning) gör just det.
grep -L "sl.h" *.c
Start och slut på rader
Vi kan tvinga grep att endast visa matchningar som antingen finns i början eller slutet av en rad. Operatorn ”^” för reguljära uttryck matchar början av en rad. Praktiskt taget alla rader i loggfilen kommer att innehålla ett mellanslag, men vi ska söka efter rader som har ett mellanslag som första tecken:
grep "^ " geek-1.log
Raderna som har ett mellanslag som första tecken – i början av raden – visas.
För att matcha slutet av raden använder du operatorn ”$” i reguljära uttryck. Vi ska söka efter rader som slutar med ”00”.
grep "00$" geek-1.log
Visningen visar rader som har ”00” som de sista tecknen.
Använda pipes med grep
Självklart kan du skicka indata till grep, skicka utdata från grep till ett annat program och ha grep inbäddat i mitten av en kedja av rör.
Låt oss säga att vi vill se alla förekomster av strängen ”ExtractParameters” i våra C-källkodsfiler. Vi vet att det kommer att vara en hel del, så vi skickar utdata till less:
grep "ExtractParameters" *.c | less
Resultatet presenteras i less.
Detta gör att du kan bläddra igenom fillistan och använda less sökfunktion.
Om vi skickar utdata från grep till wc och använder alternativet -l (rader) kan vi räkna antalet rader i källkodsfilerna som innehåller ”ExtractParameters”. (Vi skulle kunna åstadkomma detta genom att använda grep -c (count), men det här är ett smart sätt att visa hur utdata från grep fungerar.)
grep "ExtractParameters" *.c | wc -l
Med nästa kommando skickar vi utdata från ls till grep, och skickar utdata från grep till sort. Vi listar filerna i den aktuella katalogen och väljer ut de med strängen ”Aug” i sig, och sorterar dem efter filstorlek:
ls -l | grep "Aug" | sort +4n
Låt oss bryta ner det:
ls -l: Utför en lång formatlista över filerna med ls.
grep ”Aug”: Välj de rader från ls-listan som har ”Aug” i sig. Observera att detta också hittar filer som har ”Aug” i sina namn.
sort +4n: Sortera utdata från grep i den fjärde kolumnen (filstorlek).
Vi får en sorterad lista över alla filer som ändrats i augusti (oavsett år) i stigande ordning efter filstorlek.
grep: Mer än ett kommando, en viktig allierad
grep är ett oumbärligt verktyg. Det skapades 1974, och det är fortfarande mycket relevant, eftersom vi behöver det och ingenting gör det bättre.
Att kombinera grep med kunskap om reguljära uttryck tar det verkligen till nästa nivå.