GNU/Linux >> Znalost Linux >  >> Ubuntu

Jak lze zkombinovat řadu prohlášení Grep spojených dohromady do jednoho prohlášení Grep?

Zajímalo by mě, zda existuje způsob, jak zkombinovat řadu příkazů grep, kde výsledkem je „a“ výrazy spíše než „nebo“ odpovídající výrazy.

Demo níže:

./script  
     From one grep statement, I want output like this
a b c

     not like this
a
c
a b
a b c
a b c d

Slyšet je pohled na scénář.

 #!/bin/bash
 string="a
 b
 c
 d
 a b
 a b c
 a b c d"

 echo -e "\t From one grep statement I want output like this"
 echo "$string" |
 grep a |grep c |grep -v d #Correct output but pipes three grep statements

 echo -e "\n\tNot like this"
 echo "$string" |
 grep -e'a' -e'c' -e-v'd' #One grep statement but matching expressions are "or" versus "and"

Přijatá odpověď:

Nemůžete transformovat filtr grep a | grep c | grep -v d do jediného jednoduchého grep . Existují pouze složité a neefektivní způsoby. Výsledek má pomalý výkon a význam výrazu je zastřený.

Jedna kombinace příkazů tří greps

Pokud chcete spustit pouze jeden příkaz, můžete použít awk který pracuje i s regulárními výrazy a umí je kombinovat s logickými operátory. Zde je ekvivalent vašeho filtru:

awk '/a/ && /c/ && $0 !~ /d/'

Myslím, že ve většině případů není důvod zjednodušovat rouru na jeden příkaz, kromě případů, kdy výsledkem kombinace je skutečně jednoduchý výraz grep, který by mohl být rychlejší (viz výsledky níže).

Unixové systémy jsou navrženy tak, aby využívaly potrubí a spojovaly různé inženýrské sítě dohromady. Potrubní komunikace sice není nejefektivnější možná, ale ve většině případů je dostačující. Protože v dnešní době má většina nových počítačů více jader CPU, můžete „přirozeně“ využívat paralelizaci CPU pouhým použitím potrubí!

Váš původní filtr funguje velmi dobře a myslím si, že v mnoha případech awk řešení by bylo o něco pomalejší i na jednom jádru.

Porovnání výkonu

Pomocí jednoduchého programu jsem vygeneroval náhodný testovací soubor s 200 000 000 řádky, každý se 4 znaky jako náhodnou kombinací znaků a , b , c a d . Soubor má 1 GB. Během testů byl zcela načten do mezipaměti, takže žádné operace s diskem neovlivnily měření výkonu. Testy byly spuštěny na dvoujádrovém procesoru Intel.

Jeden grep

$ time ( grep -E '^[^d]*a[^d]*c[^d]*$|^[^d]*c[^d]*a[^d]*$' testfile >/dev/null )
real    3m2.752s
user    3m2.411s
sys 0m0.252s

Jeden awk

$ time ( awk '/a/ && /c/ && $0 !~ /d/' testfile >/dev/null )
real    0m54.088s
user    0m53.755s
sys 0m0.304s

Původní tři grepy zapojené

$ time ( grep a testfile | grep c | grep -v d >/dev/null )
real    0m28.794s
user    0m52.715s
sys 0m1.072s

Hybridní – kladné grepy kombinované, záporné sdružené

$ time ( grep -E 'a.*c|c.*a' testfile | grep -v d >/dev/null )
real    0m15.838s
user    0m24.998s
sys 0m0.676s

Zde vidíte, že jediný grep je velmi pomalý kvůli složitému výrazu. Původní potrubí tří grepů je docela rychlé díky dobré paralelizaci. Bez paralelizace – na jediném jádru – běží původní potrubí jen o něco rychleji než awk který jako jediný proces není paralelizován. Awk a grep pravděpodobně používají stejný kód regulárních výrazů a logika těchto dvou řešení je podobná.

Související:Kolik let je podporováno 11.10?

Jednoznačným vítězem je hybridní spojení dvou pozitivních grepů a ponechání negativního v potrubí. Zdá se, že regulární výraz s | nemá žádnou výkonnostní penalizaci.


Ubuntu
  1. Jak sloučit dvě statické knihovny do jedné?

  2. Jak mohu použít grep k zobrazení pouze názvů souborů v Linuxu?

  3. Jak zřetězit více řádků výstupu do jednoho řádku?

  1. Jak sloučit více připojení k internetu do jednoho?

  2. Jak převést video ve vysoké kvalitě na video nízké kvality?

  3. Kombinujte více unixových příkazů do jednoho výstupu

  1. Jak se přihlásit do kontejneru Lxc?

  2. Jak mohu vyhledat víceřádkový vzor v souboru?

  3. Jak mohu vyloučit adresáře z grep -R?