S terminálem: Používání regulárních výrazů II: Náhrady

V sobě předchozí článek Na základní úrovni jsem vám řekl, jak fungují jednotlivé nejpoužívanější speciální znaky regulárních výrazů. S těmito regulárními výrazy je možné provádět komplexní vyhledávání v textových souborech nebo na výstupu jiných příkazů. V tomto článku vysvětlím, jak použít příkaz sed k nalezení a nahrazení textu mnohem efektivnějším způsobem, než jednoduše změnit jeden text za jiný.

Trochu více o příkazu grep

Než začnu mluvit o sedu, chtěl bych ještě trochu komentovat příkaz grep, abych trochu dokončil to, co bylo vysvětleno v předchozím článku. Všechno, co řeknu, bude relevantní i pro tento. Později uvidíme vztah mezi tímto a vyhledáváními.

Kombinování regulárních výrazů

Mnoho zvláštních postav, o kterých jsem hovořil v předchozím článku, lze kombinovat nejen s jinými znaky, ale s celými regulárními výrazy. Způsob, jak to udělat, je použít závorky k vytvoření podvýrazu. Podívejme se na příklad. Začněme stažením textu, který můžeme použít k testování. Je to seznam frází. K tomu použijeme následující příkaz:

curl http://artigoo.com/lista-de-frases-comparativas-comicas 2>/dev/null | sed -n 's/.*\(.*\.\)<\/p>/\1/gp' > frases

 Toto vás ponechá v adresáři, kde spustíte soubor s názvem «fráze». Můžete jej otevřít, podívat se na něj a trochu se zasmát. 🙂

Nyní předpokládejme, že chceme najít fráze, které mají přesně 6 slov. Obtíž spočívá ve vytvoření regulárního výrazu, který odpovídá každému slovu. Slovo je posloupnost písmen, ať už velkých nebo malých, která by byla něco jako '[a-zA-Z]+', ale musíte také určit, že tato písmena musí být oddělena jinými znaky, které nejsou písmeny, to znamená, že by to bylo něco jako '[a-zA-Z]+[^a-zA-Z]+'. Pamatujme: „^“ jako první znak v závorkách označuje, že se chceme shodovat se znaky, které nejsou v rozsahu, a „+“ označuje 1 nebo více znaků.

Již máme regulární výraz, který odpovídá slovu. Chcete-li jej spárovat s 6, bude se muset opakovat 6krát. K tomu jsme použili klíče, ale je to k ničemu '[a-zA-Z]+[^a-zA-Z]+{6}', protože 6 by opakovalo poslední část regulárního výrazu a to, co chceme, je opakovat to všechno, takže musíme dát toto: '([a-zA-Z]+[^a-zA-Z]+){6}'. Se závorkami vytvoříme subexpresi a se složenými závorkami to opakujeme 6krát. Nyní stačí přidat „^“ vpředu a „$“ vzadu, aby odpovídal celému řádku. Příkaz je následující:

grep -E '^([a-zA-Z]+[^a-zA-Z]+){6}$' frases

A výsledek je přesně to, co jsme chtěli:

Je to více zpívané než Macarena. Jste více hotový než Luis Aguilé. Máte méně kultury než kámen. Znáte více jazyků než Cañita Brava. Má více vrásek než Tutan Khamón. O péči o dítě toho víte méně než Rambo.

Všimněte si, že jsme vložili parametr -E, protože chceme, aby "+" fungoval pomocí rozšířených regulárních výrazů. Pokud bychom použili základní, museli bychom uniknout závorce a složené závorky.

Zpětné odkazy nebo zpětné reference

Pokud máte nainstalovanou kontrolu pravopisu, pravděpodobně budete mít seznam slov /usr/share/dict/words. Pokud ne, můžete jej nainstalovat do archu pomocí:

sudo pacman -S words

Nebo v debian s:

sudo aptitude install dictionaries-common

Pokud chcete, můžete se podívat na soubor a zjistit, jaká slova má. Ve skutečnosti se jedná o odkaz na slovní soubor jazyka, ve kterém je vaše distribuce. Můžete mít nainstalovaných několik slovních souborů současně.

Ten soubor použijeme. Ukazuje se, že jsme velmi zvědaví, že známe všechny sedmimístné palindromy tam. Pro ty, kteří nevědí: Palindrom je slovo capicúa, to znamená, že se dá číst zleva doprava i zprava doleva. Zkusme následující příkaz:

grep '^\(.\)\(.\)\(.\).\3\2\1$' /usr/share/dict/words

Vypadá to trochu divně, že? Pokud to zkusíme, výsledek bude záviset na jazyce vaší distribuce a slovech ve vašem seznamu, ale v mém případě, ve španělském jazyce, bude výsledek tento:

anilin anilin válcování

Podívejme se, jak tento regulární výraz funguje.

Kromě znaků „^“ a „$“, o kterých už víme, k čemu jsou první, vidíme nalevo tři skupiny teček uzavřených v závorkách. Nenechte se zmást pruhy před každou závorkou. Mají uniknout ze závorek, protože používáme základní regulární výrazy, ale nemají žádný jiný význam. Důležité je, že žádáme o libovolné tři znaky s tečkami, ale každá z těchto teček je uzavřena v závorkách. To slouží k uložení znaků, které odpovídají těmto bodům, aby na ně bylo možné znovu odkazovat z regulárního výrazu. Toto je další použití závorek, které se později hodí při nahrazování.

To je místo, kde tři níže uvedená čísla přicházejí s lomítkem před nimi. V tomto případě je lišta důležitá. To znamená, že číslo níže je zpětná reference a odkazuje na jednu z předchozích závorek. Například: \ 1 odkazuje na první závorku, \ 2 na druhou atd.

To znamená, že s regulárním výrazem, který jsme vložili, hledáme všechna slova, která začínají libovolnými čtyřmi písmeny a poté mají písmeno, které je stejné jako třetí, další, které je stejné jako druhé a další, které je stejné jako První. Výsledkem jsou sedmipísmenné palindromy, které jsou v seznamu slov. Přesně jak jsme chtěli.

Pokud bychom používali rozšířené regulární výrazy, závorky by nemuseli uniknout, ale u rozšířených regulárních výrazů nefungují zpětné reference ve všech programech, protože nejsou standardizované. S grepem však fungují, takže to může být další způsob, jak udělat totéž. Můžete to zkusit, pokud chcete.

Náhradní výrazy: příkaz sed

Kromě vyhledávání je jedním z nejlepších použití regulárních výrazů nahrazení složitých textů. Jedním ze způsobů, jak to udělat, je příkaz sed. Síla příkazu sed jde daleko za nahrazení textu, ale tady ji k tomu použiji. Syntaxe, kterou s tímto příkazem použiji, je následující:

sed [-r] 's/REGEX/REPL/g' FICHERO

Nebo také:

COMANDO | sed [-r] 's/REGEX/REPL/g'

Kde REGEX bude vyhledávací regulární výraz a REPL bude nahrazení. Mějte na paměti, že tento příkaz skutečně nenahradí nic v souboru, který označíme, ale to, co dělá, je, že nám ukáže výsledek nahrazení v terminálu, takže se nemusíte bát příkazů, které hodlám dát další. Žádný z nich nebude upravovat žádné soubory ve vašem systému.

Začněme jednoduchým příkladem. Všichni máme v adresáři / etc různé konfigurační soubory, které mají obvykle komentáře začínající znakem „#“. Předpokládejme, že chceme vidět jeden z těchto souborů bez komentářů. Například to udělám s fstab. Můžete zkusit s tou, kterou chcete.

sed 's/#.*//g' /etc/fstab

Nebudu sem dávat výsledek příkazu, protože záleží na tom, co máte ve svém fstabu, ale pokud porovnáte výstup příkazu s obsahem souboru, uvidíte, že všechny komentáře zmizely.

V tomto příkazu je vyhledávací výraz «#.*„, To je„ # “následovaný libovolným počtem znaků, tj. Komentáři. A při nahrazení výrazu, pokud se podíváte na dva pruhy v řadě, uvidíte, že žádné nejsou, takže to, co dělá, je nahrazení komentářů ničím, to znamená jejich mazání. Jednodušší nemožné.

Nyní uděláme pravý opak. Předpokládejme, že chceme komentovat všechny řádky souboru. Zkusme to takto:

sed 's/^/# /g' /etc/fstab

Uvidíte, že ve výstupu příkazu začínají všechny řádky znakem hash a mezerou. Co jsme udělali, je nahradit začátek řádku «# «. Toto je také poměrně jednoduchý příklad, kdy text, který má být nahrazen, je vždy stejný, ale nyní to ještě trochu zkomplikujeme.

Půvabem nahrazení je, že v náhradním výrazu můžete použít zpětné reference jako ty, které jsem vám řekl dříve. Vraťme se k souboru frází, který jsme stáhli na začátku článku. Dáme do závorek všechna velká písmena, která tam jsou, ale uděláme to příkazem:

sed 's/\([A-Z]\)/(\1)/g' frases

To, co zde máme, je zpětná reference v náhradním výrazu, který odkazuje na závorky ve vyhledávacím výrazu. Závorky v náhradním výrazu jsou normální závorky. V náhradním výrazu nemají žádný zvláštní význam, jsou uvedeny tak, jak jsou. Výsledkem je, že všechna velká písmena jsou nahrazena stejným písmenem, ať je to cokoli, s kulatými závorkami.

V náhradním výrazu lze také použít další znak, je to „&“ a je nahrazen veškerým textem odpovídajícím hledanému výrazu. Příkladem toho může být uvedení všech frází v souboru do uvozovek. Toho lze dosáhnout pomocí tohoto příkazu:

sed 's/.*/"&"/g' frases

Fungování tohoto příkazu je velmi podobné předchozímu, pouze nyní nahradíme celý řádek se stejným řádkem s uvozovkami kolem něj. Protože používáme „&“, nemusíme uvádět závorky.

Některé užitečné příkazy s regulárními výrazy

Zde je několik příkazů, které považuji za užitečné nebo zvědavé a které používají regulární výrazy. U těchto příkazů je užitečnost regulárních výrazů mnohem lepší než u příkladů, které jsem dosud uvedl, ale zdálo se mi důležité vysvětlit něco o tom, jak regulární výrazy fungují, aby jim porozuměl.

  • Zobrazit sekce manuálové stránky:

man bash | grep '^[A-Z][A-Z ]*$'

Samozřejmě můžete změnit příkaz bash na cokoli chcete. A pak z člověka můžete přejít přímo do sekce, která vás zajímá, samozřejmě pomocí regulárního výrazu. Stisknutím «/» zahájíte vyhledávání a zapíšete «^ALIASES$»Přejít například do sekce ALIASES. Myslím, že toto je první použití regulárních výrazů, které jsem začal používat před několika lety. Procházení některými stránkami manuálu je bez takového triku téměř nemožné.

  • Zobrazit jména všech uživatelů stroje včetně speciálních:

sed 's/\([^:]*\).*/\1/' /etc/passwd

  • Zobrazit uživatelská jména, ale pouze ta s shellem:

grep -vE '(/false|/nologin)$' /etc/passwd | sed 's/\([^:]*\).*/\1/g'

Opravdu to lze udělat pomocí jediného regulárního výrazu, ale způsob, jak to udělat, jde nad rámec toho, co jsem vám řekl v těchto článcích, takže jsem to udělal kombinací dvou příkazů.

  • Vložte čárku před poslední tři číslice všech čísel v souboru čísel:

sed 's/\(^\|[^0-9.]\)\([0-9]\+\)\([0-9]\{3\}\)/\1\2,\3/g' numbers

Funguje pouze s čísly do 6 číslic, ale lze ji zavolat více než jednou, aby se oddělovače umístily do ostatních skupin se třemi číslicemi.

  •  Extrahujte všechny e-mailové adresy ze souboru:

grep -E '\<[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}\>' FICHERO

  • Oddělte den, měsíc a rok všech dat, která se zobrazí v souboru:

sed -r 's/([0-9]{2})[/-]([0-9]{2})[/-]([0-9]{4})/Día: \1, Mes: \2, Año: \3/g' FICHERO

  • Zjistěte naši místní IP adresu:

/sbin/ifconfig | grep 'inet .*broadcast' | sed -r 's/[^0-9]*(([0-9]+\.){3}[0-9]+).*/\1/g'

To lze také provést pomocí jediného příkazu sed, ale pro lepší jednoduchost jej rozdělím na grep a sed.

Některé užitečné adresy

Zde jsou některé adresy, které mohou být užitečné v souvislosti s regulárními výrazy:

  • Knihovna regulárních výrazů: Je to knihovna regulárních výrazů, ve které můžete hledat regulární výrazy související s tématem, které vás zajímá. Chcete-li vyhledat webové adresy, ID nebo cokoli jiného.
  • RegExr: Online kontrola regulárních výrazů. Umožňuje vám zadat text a použít na něj regulární výraz, a to buď vyhledáním, nebo nahrazením. Poskytuje informace o regulárním výrazu a máte několik možností, jak změnit jeho chování.
  • Tester regulárních výrazů: Jedná se o doplněk pro firefox, který vám umožňuje kontrolovat regulární výrazy z prohlížeče.

Závěr

To je zatím vše. Regulární výrazy jsou složité, ale užitečné. Naučit se nějakou dobu trvá, ale pokud jste jako já, hra s nimi se vám bude zdát zábavná a postupně si je osvojíte. Je to celý svět. Stále je toho hodně co říct o líných kvantifikátorech, regexu ve stylu PERL, multiline atd. A pak každý program má své vlastnosti a jeho varianty, takže nejlepší rada, kterou vám mohu dát, je vždy se podívat na dokumentaci programu, který používáte, pokaždé, když budete muset napsat regulární výraz do nového programu.

Ahoj! …AHOJ! … VZBUDIT! … CO VŠICHNI SPÍTE? 🙂

Zdroje

Některé z nápadů a příkladů regulárních výrazů v tomto článku, které jsem převzal odtud:


Zanechte svůj komentář

Vaše e-mailová adresa nebude zveřejněna. Povinné položky jsou označeny *

*

*

  1. Odpovědný za údaje: Miguel Ángel Gatón
  2. Účel údajů: Ovládací SPAM, správa komentářů.
  3. Legitimace: Váš souhlas
  4. Sdělování údajů: Údaje nebudou sděleny třetím osobám, s výjimkou zákonných povinností.
  5. Úložiště dat: Databáze hostovaná společností Occentus Networks (EU)
  6. Práva: Vaše údaje můžete kdykoli omezit, obnovit a odstranit.

  1.   živý řekl

    Mistrně !!!

    1.    hexborg řekl

      Není to tak hrozné, ale moc vám děkuji. Doufám, že se to lidem líbí. 🙂

      1.    Oskar řekl

        Líbí se mi to ha!

        1.    hexborg řekl

          Pak jsem musel udělat něco správně. LOL !! 🙂

          Moc děkuji za váš komentář.

          1.    Blaire pascal řekl

            Kurva, pokračuj v psaní, pokračuj.

          2.    hexborg řekl

            @Blaire Pascal: Komentáře jako ty to povzbuzují. 🙂 Děkuji moc !!

      2.    Město řekl

        Také se mi to líbilo ... děkuji 🙂

        1.    hexborg řekl

          Děkuji za komentář. Doufám, že napíšu ještě několik. 🙂

  2.   Marian řekl

    Vaše příspěvky jsou fantastické, hodně se naučíte, spíše se naučíte provádět úkoly elegantním a efektivním způsobem.

    Přemýšleli jste o tom, že budete shromažďovat všechny své příspěvky skriptů prostředí? Seřazeno do formátu PDF by bylo skvělým manuálem.

    Na zdraví a moc děkuji!

    1.    hexborg řekl

      Díky moc!! Není to špatný nápad. V tuto chvíli jsou jen dva, ale budu o tom přemýšlet později. 🙂

  3.   Kijov řekl

    velmi dobrý článek, 5+.

    1.    hexborg řekl

      Děkuji. Jsem rád, že se vám to líbí. 🙂

  4.   Sebastian řekl

    Vynikající! Potřebuji změnit následující výraz a nevím, jak na to:
    192.168.0.138/Server by 192.168.0.111/data
    Problém spočívá v symbolu „/“.
    Používám příkaz:
    nalézt. -name "* .txt" -exec sed -i 's / TEXT1 / TEXT2 / g' {} \;
    Co se používá k provádění tohoto typu úkolu remisivně, ale nemohu ...
    Ví někdo, jak to mám udělat?
    Hug!
    Seba

    1.    hexborg řekl

      Musíte uniknout postavě takto:

      nalézt. -name "* .txt" -exec sed -i 's / \ / Server / \ / data / g' {} \;

      Můžete také použít jiný oddělovač v sed. Nemusí to být bar. Sed umožňuje použití libovolného znaku. Bylo by to například jasnější:

      nalézt. -name "* .txt" -exec sed -i '| / Server | / data | g' {} \;

      A pokud se chystáte kopírovat a vkládat příkazy z tohoto komentáře, buďte opatrní v uvozovkách, které WordPress změní pro ty typografické. 🙂

      Zdravím.

  5.   Sebastian řekl

    Vynikající !!!!
    Toto řešení jsem hledal dlouho.
    Zde nechávám kompletní příkaz, který jsem použil

    nalézt. -name "* .txt" -exec sed -i | 192 \ .168 \ .0 \ .238 \ / server | 192 \ .168 \ .0 \ .111 \ / data | g '{} \;

    Výhodou tohoto příkazu je, že rekurzivně mění všechny soubory .txt (nebo požadovanou příponu) ... Musíte být velmi opatrní!
    Ale je to velmi užitečné !!!

    Děkuji za všechno a tisíce gratulací celé skupině.
    Vždy jsem je četl z pošty!
    Objetí
    Seba