GNU/Linux >> Znalost Linux >  >> Linux

Regex a grep:Datový tok a stavební bloky

V části Představení regulárních výrazů , Popsal jsem, co jsou a proč jsou užitečné. Nyní se podívejme hlouběji na to, jak byly vytvořeny. Protože GNU grep je jedním z nástrojů, který používám nejvíce (který poskytuje víceméně standardizovanou implementaci regulárních výrazů), použiji tuto sadu výrazů jako základ pro tento článek. Poté se podíváme na sed (další nástroj, který používá regulární výrazy) v pozdějším článku.

Všechny implementace regulárních výrazů jsou řádkové. Vzor vytvořený kombinací jednoho nebo více výrazů se porovnává s každým řádkem datového toku. Když dojde ke shodě, provede se na tomto řádku akce, jak je předepsáno použitým nástrojem.

Například když dojde ke shodě vzoru s grep , obvyklá akce je předat tento řádek STDOUT a vyřadit řádky, které neodpovídají vzoru. Jak jsme viděli v Začínáme s regulárními výrazy:příklad , -v volba obrátí tyto akce, takže řádky se shodami jsou zahozeny.

Každý řádek datového toku je vyhodnocen samostatně. Představte si každý řádek datového proudu jako záznam, kde nástroje, které používají regulární výrazy, zpracovávají vždy jeden záznam. Po nalezení shody se na řádku, který obsahuje odpovídající řetězec, provede akce definovaná používaným nástrojem.

Stavební bloky regulárních výrazů

Následující tabulka obsahuje seznam výrazů a metaznaků základních stavebních bloků implementovaných GNU grep příkaz (a většina dalších implementací regulárních výrazů) a jejich popisy. Při použití ve vzoru se každý z těchto výrazů nebo metaznaků shoduje s jedním znakem v analyzovaném datovém proudu:

Výraz Popis

Alfanumerické znaky

Doslovy

A–Z,a–z,0–9

Všechny alfanumerické a některé interpunkční znaky jsou považovány za literály. Tedy písmeno a v regulárním výrazu bude vždy odpovídat písmenu "a" v analyzovaném datovém proudu. U těchto postav neexistuje žádná nejednoznačnost. Každý doslovný znak odpovídá jednomu a pouze jednomu znaku.
. (tečka) Tečka (.) metaznak je nejzákladnější formou vyjádření. Odpovídá libovolnému jednotlivému znaku v pozici, na kterou se ve vzoru vyskytuje. Tedy vzor b.g by odpovídalo výrazům „velký“, „větší“, „pytel“, „bageta“ a „bažina“, ale nikoli výraz „pes“, „blog“, „objetí“, „zaostávání“, „roubík“, „noha“ atd. .

Výraz závorky

[seznam znaků]

GNU grep to nazývá výrazem hranatých závorek a je to stejné jako sada pro prostředí Bash. Závorky ohraničují seznam znaků, které mají odpovídat umístění jednoho znaku ve vzoru. [abcdABCD] odpovídá písmenům „a“, b, „c“ nebo „d“ ve velkých nebo malých písmenech. [a-dA-D] určuje rozsah znaků, které vytvářejí stejnou shodu. [a-zA-Z] odpovídá abecedě velkými a malými písmeny.

[:název třídy:]

Třídy postav

Toto je pokus POSIX o standardizaci regulárních výrazů. Názvy tříd by měly být zřejmé. Například [:alnum:] třída odpovídá všem alfanumerickým znakům. Další třídy jsou [:digit :] která odpovídá libovolné jedné číslici 0-9, [:alpha:] ,[:space:] , a tak dále. Všimněte si, že mohou nastat problémy kvůli rozdílům v řazení v různých lokalitách. Přečtěte si grep manuálová stránka pro podrobnosti.

^ a $

Kotvy

Tyto dva metaznaky odpovídají začátku a konci řádku. Říká se, že ukotví zbytek vzoru na začátek nebo konec řádku. Výraz ^b.g by odpovídaly pouze „velký“, „větší“, „pytel“ atd., jak je uvedeno výše, pokud se vyskytují na začátku analyzovaného řádku. Vzor b.g$ by odpovídaly výrazu „velký“ nebo „pytel“ pouze tehdy, pokud se vyskytují na konci řádku, ale nikoli „větší“.

Podívejme se na tyto stavební kameny, než budeme pokračovat s některými modifikátory. Textový soubor, který použijeme pro Experiment 3, pochází z laboratorního projektu, který jsem vytvořil pro starou linuxovou třídu, kterou jsem kdysi učil. Původně to bylo v souboru LibreOffice Writer odt, ale uložil jsem to do textového souboru ASCII. Většina formátování věcí, jako jsou tabulky, byla odstraněna, ale výsledkem je dlouhý textový soubor ASCII, který můžeme použít pro tuto sérii experimentů.

Příklad:položky obsahu

Podívejme se na příklad, abychom prozkoumali, co jsme se právě naučili. Nejprve vytvořte ~/testing adresář vašeho PWD (vytvořte jej, pokud jste to již neudělali v předchozím článku této série), a poté si stáhněte ukázkový soubor z GitHubu.

[student@studentvm1 testing]$  wget https://raw.githubusercontent.com/opensourceway/reg-ex-examples/master/Experiment_6-3.txt

Chcete-li začít, použijte less příkaz k zobrazení a prozkoumání Experiment_6-3.txt soubor na několik minut, abyste získali představu o jeho obsahu.

Nyní použijeme jednoduchý grep výrazy pro extrahování řádků ze vstupního datového toku. Obsah (TOC) obsahuje seznam projektů a jejich příslušných čísel stránek v dokumentu PDF. Vyjmime TOC začínající řádky končícími dvěma číslicemi:

[student@studentvm1 testing]$  grep [0-9][0-9]$ Experiment_6-3.txt

Tento příkaz ve skutečnosti není to, co chceme. Zobrazuje všechny řádky, které končí dvěma číslicemi, a chybí položky TOC pouze s jednou číslicí. Na to, jak zacházet s výrazem pro jednu nebo více číslic, se podíváme v pozdějším experimentu. Prohlížení celého souboru v less , mohli bychom udělat něco takového.

[student@studentvm1 testing]$ grep "^Lab Project" Experiment_6-3.txt | grep "[0-9]$"

Tento příkaz je mnohem blíže tomu, co chceme, ale není tam úplně. Dostaneme některé řádky z pozdější části dokumentu, které také odpovídají těmto výrazům. Pokud si prostudujete další řádky a podíváte se na ně v úplném dokumentu, uvidíte, proč se shodují, i když nejsou součástí obsahu.

Tento příkaz také postrádá položky obsahu, které nezačínají "Lab Project." Někdy je tento výsledek tím nejlepším, co můžete udělat, a poskytuje lepší pohled na TOC, než jsme měli dříve. Podíváme se, jak zkombinovat tyto dva grep instance do jedné v pozdějším experimentu.

Nyní tento příkaz trochu upravíme a použijeme výraz POSIX. Všimněte si dvojitých hranatých závorek ([[]] ) kolem toho:

[student@studentvm1 testing]$ grep "^Lab Project" Experiment_6-3.txt | grep "[[:digit:]]$"

Jednotlivé složené závorky generují chybovou zprávu.

Tento příkaz dává stejné výsledky jako předchozí pokus.

Příklad:systemd

Hledejme ve stejném souboru něco jiného:

[student@studentvm1 testing]$ grep systemd Experiment_6-3.txt

Tento příkaz vypíše všechny výskyty "systemd" v souboru. Zkuste použít -i možnost, abyste zajistili, že získáte všechny instance, včetně těch, které začínají velkými písmeny (oficiální forma "systemd" je všechna malá). Nebo můžete změnit doslovný výraz na Systemd .

Spočítejte počet řádků obsahujících řetězec systemd . Vždy používám -i abyste zajistili, že budou nalezeny všechny výskyty hledaného výrazu bez ohledu na velikost písmen:

[student@studentvm1 testing]$ grep -i systemd Experiment_6-3.txt | wc
20      478     3098

Jak vidíte, mám 20 řádků a vy byste měli mít stejný počet.

Příklad:Metaznaky

Zde je příklad shody metaznaku:levá závorka ([ ). Nejprve to zkusme, aniž bychom dělali něco zvláštního:

[student@studentvm1 testing]$  **grep -i "[" Experiment_6-3.txt**
grep: Invalid regular expression

K této chybě dochází, protože [ je interpretován jako metaznak. Musíme utéct tento znak se zpětným lomítkem (\ ), aby byl interpretován jako doslovný znak a nikoli jako metaznak:

[student@studentvm1 testing]$ grep -i "\[" Experiment_6-3.txt

Většina metaznaků ztrácí svůj zvláštní význam, když jsou použity ve výrazech v závorkách:

  • Zahrnout doslovný ] , umístěte jej na první místo v seznamu.
  • Chcete-li zahrnout doslovný ^ , umístěte ji kamkoli, ale první.
  • Chcete-li zahrnout doslovný [ , umístěte jej jako poslední.

Opakování

Regulární výrazy lze upravit pomocí operátorů, které umožňují zadat nula, jedno nebo více opakování znaku nebo výrazu. Tyto operátory opakování jsou umístěny bezprostředně za doslovný znak nebo metaznak použitý ve vzoru:

Operátor Popis
?

V regulárních výrazech je ? znamená nula nebo jeden výskyt nejvýše předchozího znaku. Takže například drives? odpovídá „drive“ a „drives“, ale nikoli „driver“. Tento výsledek se trochu liší od chování ? v globu.

* Znak před * bude bez omezení nula nebo více shod. V tomto příkladu drives* odpovídá „drive“, „drives“ a „drivesss“, ale nikoli „řidič“. Opět je to trochu odlišné od chování * v globu.
+ Znak před + bude odpovídat jednou nebo vícekrát. Aby došlo ke shodě, musí znak v řádku existovat alespoň jednou. Jako jeden příklad, drives+ odpovídá „drives“ a „drivesss“, ale nikoli „drive“ nebo „driver.“
{n} Tento operátor odpovídá předchozímu znaku přesně nkrát. Výraz drives{2} odpovídá „drivess“, ale nikoli „drives“, „drivesss“, „drivesss“ nebo libovolnému počtu koncových znaků „s“. Protože však "drivesssss" obsahuje řetězec drivess , na tomto řetězci dojde ke shodě, takže řádek bude odpovídat grep .
{n,} Tento operátor odpovídá předchozímu znaku n nebo vícekrát. Výraz drives{2,} odpovídá výrazu „drives“, ale nikoli „drive“, „drives“, „drivess“, „drives“ nebo libovolnému počtu koncových znaků „s“. Protože "drivesssss" obsahuje řetězec drivess , dojde ke shodě.
{,m} Tento operátor odpovídá předchozímu znaku maximálně mkrát. Výraz drives{,2} odpovídá výrazům „drives“, „drives“ a „drivess“, ale nikoli „drivesss“ ani žádnému počtu koncových znaků „s“. Ještě jednou, protože "drivesssss" obsahuje řetězec drivess , dojde ke shodě.
{n,m} Tento operátor odpovídá předchozímu znaku alespoň nkrát, ale ne více než mkrát. Výraz drives{1,3} odpovídá „drivess“, „drivess“ a „drivesss“, ale nikoli „drivessss“ ani žádnému počtu koncových znaků „s“. Ještě jednou, protože "drivesssss" obsahuje odpovídající řetězec, dojde ke shodě.

Jako příklad spusťte každý z následujících příkazů a pečlivě prozkoumejte výsledky, abyste pochopili, co se děje:

[student@studentvm1 testing]$  **grep -E files? Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives*" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives+" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2,}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{,2}" Experiment_6-3.txt**
[student@studentvm1 testing]$  **grep -Ei "drives{2,3}" Experiment_6-3.txt**

Nezapomeňte experimentovat s těmito modifikátory na jiném textu v ukázkovém souboru.

Modifikátory metaznaků

Stále existují některé zajímavé a důležité modifikátory, které musíme prozkoumat:

Modifikátor Popis
< Tento speciální výraz odpovídá prázdnému řetězci na začátku slova. Výraz <fun by odpovídalo výrazům „zábava“ a „funkce“, ale nikoli výrazu „refund.“
> Tento speciální výraz odpovídá normální mezerě nebo prázdnému (" ") řetězci na konci slova a také interpunkci, která se obvykle vyskytuje v jednoznakovém řetězci na konci slova. Tedy environment> odpovídá výrazům „životní prostředí“, „prostředí“ a „životní prostředí“, ale nikoli „prostředí“ nebo „životní prostředí“.
^ Ve výrazu znakové třídy tento operátor neguje seznam znaků. Tedy, zatímco třída [a-c] odpovídá „a“, „b“ nebo „c“ v dané pozici vzoru, třídě [^a-c] odpovídá čemukoli kromě „a“, „b“ nebo „c.“
| Při použití v regulárním výrazu | metaznak je logický operátor "nebo". Oficiálně se nazývá infix nebo alternace operátor. S tím jsme se již setkali v Začínáme s regulárními výrazy:příklad , kde jsme viděli, že regulární výraz "Team|^\s*$" znamená „řádek s 'Tým' nebo (| ) prázdný řádek, který obsahuje nula, jeden nebo více mezer, jako jsou mezery, tabulátory a další netisknutelné znaky."
( and ) Závorky ( and ) nám umožňují zajistit specifickou sekvenci porovnávání vzorů, která by mohla být použita pro logická porovnávání v programovacím jazyce.

Nyní máme způsob, jak určit hranice slov pomocí \< a \> metaznaky. To znamená, že nyní můžeme být se svými vzory ještě explicitnější. Logiku můžeme použít i ve složitějších vzorcích.

Jako příklad začněte s několika jednoduchými vzory. Tento první vybere všechny instance drives ale ne drive , drivess , nebo další koncové znaky "s":

 [student@studentvm1 testing]$  **grep -Ei "\<drives\>" Experiment_6-3.txt**

Nyní vytvoříme vyhledávací vzor pro nalezení odkazů na tar (příkaz tape archive) a související odkazy. První dvě iterace zobrazují více než jen tar -související řádky:

[student@studentvm1 testing]$ grep -Ei "tar" Experiment_6-3.txt
[student@studentvm1 testing]$ grep -Ei "\<tar" Experiment_6-3.txt
[student@studentvm1 testing]$  grep -Ein "\<tar\>" Experiment_6-3.txt

-n volba v posledním příkazu výše zobrazí čísla řádků pro každý řádek, ve kterém došlo ke shodě. Tato možnost může pomoci při hledání konkrétních instancí vyhledávacího vzoru.

Tip: Odpovídající řádky dat mohou přesahovat jednu obrazovku, zejména při prohledávání velkého souboru. Výsledný datový tok můžete propojit pomocí obslužného programu less a pak použít nástroj less search, který také implementuje regulární výrazy, ke zvýraznění výskytů shod s vyhledávacím vzorem. Argument hledání v less je:\<tar\> .

Tento další vzor hledá v našem testovacím dokumentu „skript prostředí“, „program prostředí“, „proměnná prostředí“, „prostředí prostředí“ nebo „výzva prostředí“. Závorky mění logické pořadí, ve kterém jsou řešena porovnání vzorů:

[student@studentvm1 testing]$ grep -Eni "\<shell (script|program|variable|environment|prompt)" Experiment_6-3.txt

Poznámka: Tento článek je mírně upravená verze kapitoly 6 z druhého dílu mé knihy o Linuxu „Using and Administering Linux:Zero to SysAdmin“, která má vyjít na Apress koncem roku 2019.

Odstraňte závorky z předchozího příkazu a spusťte jej znovu, abyste viděli rozdíl.

Zabalení

Ačkoli jsme nyní prozkoumali základní stavební kameny regulárních výrazů v grep , existuje nekonečná řada způsobů, jak je lze kombinovat a vytvářet složité, ale elegantní vyhledávací vzory. Nicméně grep je vyhledávací nástroj a neposkytuje žádnou přímou možnost upravit nebo upravit řádek textu v datovém toku, když je nalezena shoda. K tomuto účelu potřebujeme nástroj jako sed , kterému se budu věnovat ve svém dalším článku.


Linux
  1. Extrahování a zobrazení dat pomocí awk

  2. Použít příkaz Grep a vyhledat?

  3. Základy Vhosts a serverových bloků

  1. Výzva a příslib velkých dat

  2. Přehled CCPA a GDPR

  3. Časté dotazy k systémovému disku a datovému disku

  1. Proč jsou data důležitá a jak je chránit

  2. Řez / Grep A Df -h?

  3. Grep And Tail -f?