10 praktických príkladov príkazov Grep pre vývojárov
Príkaz grep sa používa na vyhľadanie vzorov v súboroch. Tento tutoriál ukazuje niektoré z najbežnejších príkladov príkazov grep, ktoré by boli špeciálne prospešné pre vývojárov softvéru.
Nedávno som začal pracovať s Asciidoctor.js a na šablónach Asciidoctor.js-pug a Asciidoctor-template. js projekt.
Nie je vždy ľahké byť okamžite efektívny, keď sa prvýkrát ponoríte do kódovej základne obsahujúcej niekoľko tisíc riadkov. Ale mojou tajnou zbraňou, ako nájsť cestu cez toľko riadkov kódu, je nástroj grep
.
Podelím sa s vami o to, ako používať príkaz grep v Linuxe s príkladmi.
Užitočné príklady príkazov grep v systéme Linux v reálnom živote
Ak sa pozriete do man
, uvidíte krátky popis nástroja grep
: “tlač čiary zodpovedajúce vzoru. ”
Nenechajte sa však zmiasť takouto skromnou definíciou: grep
je jedným z najužitočnejších nástrojov v sade nástrojov Unix a existuje nespočetné množstvo príležitostí na jeho použitie hneď, ako pracujete s textovými súbormi.
Vždy je lepšie mať príklady z reálneho sveta, aby ste sa naučili, ako veci fungujú. Na ilustráciu niektorých možností grep
teda použijem zdrojový strom Asciidoctor.js.
Tento zdrojový strom si môžete stiahnuť z GitHubu a ak chcete, môžete si dokonca pozrieť rovnakú sadu zmien, ktorú som použil pri písaní tohto článku. To zaistí, že získate výsledky úplne identické s tými, ktoré sú opísané vo zvyšku tohto článku:
git clone https://github.com/asciidoctor/asciidoctor.js
cd asciidoctor.js
git checkout v1.5.6-rc.1
1. Nájdite všetky výskyty reťazca (základné použitie)
Asciidoctor.js podporuje Nashorn JavaScript engine pre platformu Java. Nepoznám Nashorn, takže by som mohol využiť túto príležitosť a dozvedieť sa o ňom viac preskúmaním častí projektu odkazujúcich na tento JavaScript engine.
Ako východiskový bod som skontroloval, či existujú nejaké nastavenia súvisiace s Nashornom v súbore package.json
popisujúce závislosti projektu:
linux@handbook:~$ grep nashorn package.json
"test": "node npm/test/builder.js && node npm/test/unsupported-features.js && node npm/test/jasmine-browser.js && node npm/test/jasmine-browser-min.js && node npm/test/jasmine-node.js && node npm/test/jasmine-webpack.js && npm run test:karmaBrowserify && npm run test:karmaRequirejs && node npm/test/nashorn.js",
Áno, zrejme tam boli nejaké testy špecifické pre Nashorn. Poďme to teda preskúmať trochu viac.
2. Vyhľadávanie v súbore súborov bez rozlišovania malých a veľkých písmen
Teraz sa chcem bližšie pozrieť na súbory z adresára ./npm/test/
, v ktorých sa výslovne spomína Nashorn.
Vyhľadávanie bez ohľadu na malé a veľké písmená (možnosť -i
) je tu pravdepodobne lepšie, pretože potrebujem nájsť odkazy na nashorn
a Nashorn
(alebo akékoľvek iné kombinácia veľkých a malých písmen):
linux@handbook:~$ grep -i nashorn npm/test/*.js
npm/test/nashorn.js:const nashornModule = require('../module/nashorn');
npm/test/nashorn.js:log.task('Nashorn');
npm/test/nashorn.js:nashornModule.nashornRun('jdk1.8.0');
V skutočnosti tu bola užitočná necitlivosť na malé a veľké písmená. V opačnom prípade by som vynechal príkaz require('../module/nashorn')
. Nepochybne by som mal neskôr preskúmať tento súbor podrobnejšie.
3. Nájdite všetky nezhodné súbory
Mimochodom, sú v adresári npm/test/
nejaké súbory, ktoré nie sú špecifické pre Nashorm? Na zodpovedanie tejto otázky môžeme použiť možnosť „vytlačiť nezodpovedajúce súbory“ funkcie grep (možnosť -L
):
sh$ grep -iL nashorn npm/test/*
npm/test/builder.js
npm/test/jasmine-browser-min.js
npm/test/jasmine-browser.js
npm/test/jasmine-node.js
npm/test/jasmine-webpack.js
npm/test/unsupported-features.js
Všimnite si, ako sa s voľbou -L
výstup grep
zmenil tak, že zobrazuje iba názvy súborov. Žiadny z vyššie uvedených súborov teda neobsahuje reťazec „nashorn“ (bez ohľadu na veľkosť písmen). To neznamená, že nejako nesúvisia s touto technológiou, ale prinajmenšom nie sú prítomné písmená „n-a-s-h-o-r-n “.
4. Hľadanie vzorov do skrytých súborov a rekurzívne do podadresárov
Posledné dva príkazy používali vzor shell glob na odovzdanie zoznamu súborov na preskúmanie príkazu grep
.
Má to však určité obmedzenia: hviezdička (*
) nebude zodpovedať skrytým súborom. Nebude sa zhodovať ani so súbormi (v konečnom dôsledku) obsiahnutými v podadresároch.
Riešením by bolo skombinovať grep
s príkazom find namiesto spoliehania sa na vzor shell glob:
# This is not efficient as it will spawn a new grep process for each file
linux@handbook:~$ find npm/test/ -type f -exec grep -iL nashorn \{} \;
# This may have issues with filenames containing space-like characters
linux@handbook:~$ grep -iL nashorn $(find npm/test/ -type f)
Ako som spomenul v komentároch v bloku kódu vyššie, každé riešenie má nevýhody.
Čo sa týka názvov súborov obsahujúcich znaky podobné medzerám, nechám vás preskúmať možnosť grep -z
, ktorá v kombinácii s voľbou -print0
príkazu find
, môže tento problém zmierniť. Neváhajte použiť sekciu komentárov na konci tohto článku a podeľte sa o svoje nápady na túto tému!
Lepším riešením by však bolo použitie „rekurzívnej“ možnosti grep. S touto voľbou zadáte na príkazovom riadku koreň vášho vyhľadávacieho stromu (počiatočný adresár) namiesto explicitného zoznamu názvov súborov na preskúmanie.
S voľbou -r
grep vyhľadá všetky súbory v zadanom adresári, vrátane skrytých, a potom rekurzívne zostúpi do ľubovoľného podadresára:
linux@handbook:~$ grep -irL nashorn npm/test/npm/
npm/test/builder.js
npm/test/jasmine-browser-min.js
npm/test/jasmine-browser.js
npm/test/jasmine-node.js
npm/test/jasmine-webpack.js
npm/test/unsupported-features.js
V skutočnosti by som s touto možnosťou mohol tiež začať svoj prieskum o úroveň vyššie, aby som zistil, že existujú testy bez npm, ktoré sa zameriavajú aj na Nashorn:
linux@handbook:~$ grep -irL nashorn npm/
Nechal som vás otestovať tento príkaz, aby ste videli jeho výsledok; ale ako tip môžem povedať, že by ste mali nájsť oveľa viac zodpovedajúcich súborov!
5. Filtrovanie súborov podľa ich názvu (pomocou regulárnych výrazov)
Zdá sa teda, že v tomto projekte existujú určité testy špecifické pre Nashorn. Keďže Nashorn je Java, ďalšia otázka, ktorá by mohla byť položená, by bola „existujú nejaké zdrojové súbory Java v projekte, ktoré výslovne uvádzajú Nashorn? ”.
V závislosti od verzie grep
, ktorú používate, existujú aspoň dve riešenia na odpoveď na túto otázku.
Prvým je použiť grep
na nájdenie všetkých súborov obsahujúcich vzor „nashorn“ a potom presmerovať výstup tohto prvého príkazu do druhej inštancie grep
odfiltrujúcej non-java zdrojové súbory:
linux@handbook:~$ grep -ir nashorn ./ | grep "^[^:]*\.java"
./spec/nashorn/AsciidoctorConvertWithNashorn.java:public class AsciidoctorConvertWithNashorn {
./spec/nashorn/AsciidoctorConvertWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/AsciidoctorConvertWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/asciidoctor-convert.js"));
./spec/nashorn/BasicJavascriptWithNashorn.java:public class BasicJavascriptWithNashorn {
./spec/nashorn/BasicJavascriptWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/BasicJavascriptWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/basic.js"));
Prvá polovica príkazu by už mala byť zrozumiteľná. Ale čo tá časť „^[\^:]*\\.java“?
Ak nezadáte možnosť -F
, grep
predpokladá, že vzor vyhľadávania je regulárny výraz. To znamená, že okrem obyčajných znakov, ktoré sa budú zhodovať doslovne, máte prístup k množine metaznakov na opis zložitejších vzorov. Vzor, ktorý som použil vyššie, bude zodpovedať iba:
^
začiatok riadku[^:]*
, za ktorým nasleduje sekvencia ľubovoľných znakov okrem dvojbodky\.
, za ktorým nasleduje bodka (bodka má v regulárnych výrazoch špeciálny význam, takže som ju musel chrániť spätnou lomkou, aby som vyjadril, že chcem doslovný zápas)java
a za ním štyri písmená „java. “
V praxi, keďže grep
použije dvojbodku na oddelenie názvu súboru od kontextu, ponechám len riadky s .java
v sekcii názvu súboru. Stojí za zmienku, že by sa zhodovali aj s .javascript
názvami súborov. Toto je niečo, čo som si nechal skúsiť vyriešiť sám, ak chceš.
6. Filtrovanie súborov podľa ich názvu pomocou grep
Regulárne výrazy sú mimoriadne silné. V tomto konkrétnom prípade sa to však zdá byť prehnané. Nehovoriac o vyššie uvedenom riešení, trávime čas skúmaním všetkých súborov pri hľadaní vzoru „nashorn“ – väčšina výsledkov sa zahodí v druhom kroku potrubia.
Ak používate GNU verziu grep
, čo je pravdepodobné, ak používate Linux, máte však iné riešenie s voľbou --include
. Toto prikáže grep
vyhľadávať iba v súboroch, ktorých názov sa zhoduje s daným vzorom glob:
linux@handbook:~$ grep -ir nashorn ./ --include='*.java'
./spec/nashorn/AsciidoctorConvertWithNashorn.java:public class AsciidoctorConvertWithNashorn {
./spec/nashorn/AsciidoctorConvertWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/AsciidoctorConvertWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/asciidoctor-convert.js"));
./spec/nashorn/BasicJavascriptWithNashorn.java:public class BasicJavascriptWithNashorn {
./spec/nashorn/BasicJavascriptWithNashorn.java: ScriptEngine engine = engineManager.getEngineByName("nashorn");
./spec/nashorn/BasicJavascriptWithNashorn.java: engine.eval(new FileReader("./spec/nashorn/basic.js"));
7. Hľadanie slov
Zaujímavosťou projektu Asciidoctor.js je, že ide o viacjazyčný projekt. Vo svojom jadre je Asciidoctor napísaný v Ruby, takže na to, aby bol použiteľný vo svete JavaScriptu, musí byť „transpilovaný“ pomocou Opal, kompilátora zdroja do zdroja z Ruby do JavaScriptu. Ďalšia technológia, o ktorej som predtým nevedel.
Takže po preskúmaní špecifík Nashornu som si pridelil úlohu lepšie porozumieť Opal API. Ako prvý krok v tomto pátraní som prehľadal všetky zmienky o globálnom objekte Opal
v súboroch JavaScript projektu. Môže sa objaviť v afektoch (Opal =
), prístupe členov (Opal.
) alebo možno dokonca v iných kontextoch. Regulárny výraz by urobil trik. Avšak opäť, grep
má nejaké jednoduchšie riešenie na vyriešenie tohto bežného prípadu použitia. Pomocou voľby -w
sa budú zhodovať iba slová, teda vzory, pred ktorými a za ktorými nasleduje neslovný znak. Neslovný znak je buď začiatok riadku, koniec riadku alebo akýkoľvek znak, ktorý nie je písmenom, ani číslicou, ani podčiarkovníkom:
linux@handbook:~$ grep -irw --include='*.js' Opal .
...
8. vyfarbenie výstupu
Nekopíroval som výstup predchádzajúceho príkazu, pretože existuje veľa zhôd. Keď je výstup takto hustý, možno budete chcieť pridať trochu farby, aby ste uľahčili pochopenie. Ak to ešte nie je predvolene nakonfigurované vo vašom systéme, môžete túto funkciu aktivovať pomocou možnosti GNU --color
:
linux@handbook:~$ grep -irw --color=auto --include='*.js' Opal .
...
Mali by ste získať rovnaký dlhý výsledok ako predtým, ale tentoraz by sa hľadaný reťazec mal zobraziť farebne, ak to tak ešte nebolo.
9. Počítanie zhodných riadkov alebo zhodných súborov
Dvakrát som spomenul, že výstup predchádzajúcich príkazov bol veľmi dlhý. Ako dlho presne?
linux@handbook:~$ grep -irw --include='*.js' Opal . | wc -l
86
To znamená, že máme celkovo 86 zodpovedajúcich riadkov vo všetkých skúmaných súboroch. Koľko rôznych súborov sa však zhoduje? Pomocou voľby -l
môžete obmedziť výstup grep
na zodpovedajúce súbory namiesto zobrazovania zhodných <linky. Takže táto jednoduchá zmena povie, koľko súborov sa zhoduje:
linux@handbook:~$ grep -irwl --include='*.js' Opal . | wc -l
20
Ak vám to pripomína možnosť -L
, žiadne prekvapenie: keďže je to pomerne bežné, na rozlíšenie doplnkových možností sa používajú malé/veľké písmená. -l
zobrazí zodpovedajúce názvy súborov. -L
zobrazuje nezhodné názvy súborov. V ďalšom príklade vám dovolím skontrolovať si v príručke možnosti -h
/-H
.
Zatvorme túto zátvorku a vráťme sa k našim výsledkom: 86 zodpovedajúcich riadkov. 20 zodpovedajúcich súborov. Ako sú však distribuované zodpovedajúce riadky v zodpovedajúcich súboroch? Môžeme vedieť, že pomocou voľby -c
v grep
, ktorá spočíta počet zhodných riadkov na skúmaný súbor (vrátane súborov s nulovou zhodou):
linux@handbook:~$ grep -irwc --include='*.js' Opal .
...
Tento výstup často potrebuje nejaké následné spracovanie, pretože zobrazuje svoje výsledky v poradí, v akom boli súbory preskúmané, a obsahuje aj súbory bez akejkoľvek zhody – niečo, čo nás zvyčajne nezaujíma. To posledné sa dá celkom ľahko vyriešiť:
linux@handbook:~$ grep -irwc --include='*.js' Opal . | grep -v ':0$'
Čo sa týka objednávania vecí, na koniec kanála môžete pridať príkaz sort:
linux@handbook:~$ grep -irwc --include='*.js' Opal . | grep -v ':0$' | sort -t: -k2n
Presný význam možností, ktoré som použil, som vám umožnil skontrolovať v príručke príkazu sort
. Nezabudnite sa podeliť o svoje zistenia pomocou sekcie komentárov nižšie!
10. Nájdenie rozdielu medzi dvoma zhodnými množinami
Ak si pamätáte, pred niekoľkými príkazmi som hľadal slovo „Opál. “ Ak však hľadám v rovnakej množine súborov všetky výskyty reťazca „Opal“, dostanem ďalších asi dvadsať odpovedí:
linux@handbook:~$ grep -irw --include='*.js' Opal . | wc -l
86
linux@handbook:~$ grep -ir --include='*.js' Opal . | wc -l
105
Bolo by zaujímavé nájsť rozdiel medzi týmito dvoma súbormi. Aké sú teda riadky obsahujúce štyri písmená „opál“ v rade, ale kde tieto štyri písmená netvoria celé slovo?
Nie je také ľahké odpovedať na túto otázku. Pretože rovnaký riadok môže obsahovať obaja slovo Opál, ako aj nejaké väčšie slovo obsahujúce tieto štyri písmená. Ale ako prvé priblíženie môžete použiť tento kanál:
linux@handbook:~$ grep -ir --include='*.js' Opal . | grep -ivw Opal
./npm/examples.js: const opalBuilder = OpalBuilder.create();
./npm/examples.js: opalBuilder.appendPaths('build/asciidoctor/lib');
./npm/examples.js: opalBuilder.appendPaths('lib');
...
Zdá sa, že mojou ďalšou zastávkou by bolo preskúmanie objektu opalBuilder
, ale to bude na iný deň.
Posledné slovo
Samozrejme, že nepochopíte organizáciu projektu a tým menej architektúru kódu, ak zadáte pár príkazov grep
!
Zdá sa mi však, že tento príkaz je nevyhnutný na identifikáciu referenčných hodnôt a východiskových bodov pri skúmaní novej kódovej základne.
Dúfam teda, že vám tento článok pomohol pochopiť silu príkazu grep
a že si ho pridáte do svojej truhlice s nástrojmi. Bezpochyby nebudete ľutovať!