Vorrei ottenere la corrispondenza multi pattern con AND tra i modelli, vale a dire equivalente allesecuzione di diversi greps in una sequenza:

grep pattern1 | grep pattern2 | ... 

Quindi come convertirlo in qualcosa di simile?

grep pattern1 & pattern2 & pattern3 

Vorrei usare un singolo grep perché sto costruendo argomenti dinamicamente, quindi tutto deve stare in una stringa. Luso del filtro è una funzionalità di sistema, non grep, quindi non è un argomento per esso.


Non confondere questa domanda con:

grep "pattern1\|pattern2\|..." 

Questa è una OR corrispondenza di più pattern.

Commenti

Risposta

agrep può farlo con questa sintassi:

agrep "pattern1;pattern2" 

Con GNU grep, quando viene creato w ith supporto PCRE, puoi fare:

grep -P "^(?=.*pattern1)(?=.*pattern2)" 

Con ast grep :

grep -X ".*pattern1.*&.*pattern2.*" 

(aggiunta di .* s come <x>&<y> trova stringhe che corrispondono sia a <x> che a <y> esattamente , a&b non corrisponderebbe mai in quanto” non esiste alcuna stringa di questo tipo che può essere sia a che b allo stesso tempo).

Se i pattern non si sovrappongono, potresti anche essere in grado di:

grep -e "pattern1.*pattern2" -e "pattern2.*pattern1" 

Il miglior modo portatile è probabilmente con awk come già accennato:

awk "/pattern1/ && /pattern2/" 

Con sed:

sed -e "/pattern1/!d" -e "/pattern2/!d" 

Tieni presente che tutti avranno una sintassi delle espressioni regolari diversa.

Commenti

  • La sintassi agrep non funziona per io … in quale versione era stato introdotto?
  • @Raman 2.04 del 1992 lo aveva già. ‘ non ho motivo di credere che ‘ non fosse presente fin dallinizio. Le versioni più recenti (dopo il 1992) di agrep possono essere trovate incluse in glimpse / webglimpse . Forse hai unimplementazione diversa. Tuttavia, ho commesso un errore con la versione ast-grep, lopzione per espressioni regolari aumentate è -X, non -A.
  • @St é phaneChazelas Grazie, ho agrep 0.8.0 su Fedora 23. Sembra essere un agrep diverso da quello a cui fai riferimento.
  • @Raman, il tuo suona come TRE agrep .
  • @Techiee, o semplicemente awk '/p1/ && /p2/ {n++}; END {print 0+n}'

Risposta

Non hai specificato la versione di grep, questo è importante. Alcuni motori regexp consentono più corrispondenze raggruppate da AND utilizzando “& “ma questa non è una funzionalità standard e non portabile. Ma almeno GNU grep non lo supporta.

OTOH puoi semplicemente sostituire grep con sed, awk, perl, ecc. . (elencati in ordine di peso crescente). Con awk, il comando sarebbe

 awk "/regexp1/ && /regexp2/ && /regexp3/ { print; }" 

e può essere costruito per essere specificato nella riga di comando in modo semplice.

Commenti

  • Ricorda solo che awk utilizza ERE ‘, ad es. lequivalente di grep -E, in contrasto con i BRE ‘ utilizzati da grep.
  • awk ‘ Le espressioni regolari sono chiamate ERE, ma in realtà ‘ sono un po idiosincratico. Probabilmente qui ci sono più dettagli di quanto chiunque voglia: wiki.alpinelinux.org/wiki/Regex
  • Grazie, grep 2.7.3 ( openSUSE). Ti ho votato positivamente, ma terrò la domanda aperta per un po , forse cè qualche trucco per grep (non che non mi piaccia awk – semplicemente sapere di più è meglio).
  • Lazione predefinita è stampare la riga corrispondente in modo che la parte { print; } non sia ‘ in realtà qui necessaria o utile.

Risposta

Se patterns contiene un pattern per riga, puoi fare qualcosa del genere:

 awk "NR==FNR{a[$0];next}{for(i in a)if($0!~i)next}1" patterns -  

Oppure questo corrisponde a sottostringhe invece di regolare espressioni:

 awk "NR==FNR{a[$0];next}{for(i in a)if(!index($0,i))next}1" patterns -  

Per stampare tutto invece di nessuna riga dellinput nel se patterns è vuoto, sostituisci NR==FNR con FILENAME==ARGV[1] o con ARGIND==1 in gawk.

Queste funzioni stampano le righe di STDIN che contengono ogni stringa specificata come argomento come sottostringa. ga sta per grep all e gai ignora maiuscole e minuscole.

 ga(){ awk "FILENAME==ARGV[1]{a[$0];next}{for(i in a)if(!index($0,i))next}1" <(printf %s\\n "$@") -; } gai(){ awk "FILENAME==ARGV[1]{a[tolower($0)];next}{for(i in a)if(!index(tolower($0),i))next}1" <(printf %s\\n "$@") -; }  

Commenti

  • risposta chiara che affronta diversi casi duso e lavori (verificato su macos)

Risposta

grep pattern1 | grep pattern2 | ...

Vorrei usare un singolo grep perché sto costruendo argomenti dinamicamente , quindi tutto deve stare in una stringa

È effettivamente possibile costruire la pipeline in modo dinamico (senza ricorrere a eval):

 # Executes: grep "$1" | grep "$2" | grep "$3" | ... function chained-grep { local pattern="$1" if [[ -z "$pattern" ]]; then cat return fi shift grep -- "$pattern" | chained-grep "$@" } cat something | chained-grep all patterns must match order but matter dont  

Tuttavia, probabilmente non è una soluzione molto efficiente.

Commenti

  • Utilizza chained-grep() o function chained-grep ma non function chained-grep(): unix.stackexchange.com/questions/73750/…
  • Puoi descrivere qual è il trucco? Puoi aggiungerlo alla risposta ( senza ” Modifica: “, ” Aggiornare: ” o simile) modificandolo ?
  • Riformulata la risposta per rendere più chiaro il trucco (es .: costruire dinamicamente una shell pipeline)

Risposta

git grep

Ecco la sintassi utilizzando git grep combinazione di più pattern utilizzando espressioni booleane :

git grep --no-index -e pattern1 --and -e pattern2 --and -e pattern3 

Il comando precedente stamperà le righe che corrispondono a tutti i modelli contemporaneamente.

--no-index Cerca i file nella directory corrente che non è gestita da Git.

Seleziona man git-grep per assistenza.

Vedi anche:

Per loperazione OR , vedere:

Commenti

  • Ottima risposta. Grazie.

Risposta

Ecco la mia opinione, e funziona per parole su più righe:

Utilizza find . -type f seguito da altrettanti
-exec grep -q "first_word" {} \;
e lultima parola chiave con
-exec grep -l "nth_word" {} \;

-q silenzioso / silenzioso
-l mostra file con corrispondenze

Il seguente elenco di nomi di file contenente le parole “coniglio” e “buco”:
find . -type f -exec grep -q "rabbit" {} \; -exec grep -l "hole" {} \;

Commenti

  • Se guardi attentamente, potresti apprendere che questa non è la funzionalità richiesta dalla domanda.

Risposta

ripgrep

Ecco lesempio che utilizza rg :

rg -N "(?P<p1>.*pattern1.*)(?P<p2>.*pattern2.*)(?P<p3>.*pattern3.*)" file.txt 

È uno degli strumenti di grepping più veloci, poiché si basa su Rust “motore di regex che utilizza automi finiti, SIMD e ottimizzazioni letterali aggressive per rendere la ricerca molto veloce.

Vedi anche la richiesta di funzionalità correlate su GH-875 .

Risposta

Per trovare tutte le parole (o gli schemi), puoi eseguire grep in un ciclo for. Il vantaggio principale qui è la ricerca da un elenco di espressioni regolari .

Un esempio reale:

# File "search_all_regex_and_error_if_missing.sh" find_list="\ ^a+$ \ ^b+$ \ ^h+$ \ ^d+$ \ " for item in $find_list; do if grep -E "$item" file_to_search_within.txt then echo "$item found in file." else echo "Error: $item not found in file. Exiting!" exit 1 fi done 

Ora eseguiamolo su questo file:

hhhhhhhhhh aaaaaaa bbbbbbbbb ababbabaabbaaa ccccccc dsfsdf bbbb cccdd aa caa 
$ ./search_all_regex_and_error_if_missing.sh aaaaaaa aa ^a+$ found in file. bbbbbbbbb bbbb ^b+$ found in file. hhhhhhhhhh ^h+$ found in file. Error: ^d+$ not found in file. Exiting! 

Commenti

  • La tua logica è difettosa – Ho chiesto ALL, il tuo codice funziona come operatore OR, non AND. E btw. Per quello (OR) è una soluzione molto più semplice data direttamente nella domanda.
  • @greenoldman La logica è semplice: il for ripeterà TUTTE le parole / schemi nellelenco, e se si trova nel file, lo stamperà. Quindi rimuovi semplicemente il else se ‘ non hai bisogno di unazione nel caso in cui la parola non sia stata trovata.
  • Capisco la tua logica e la mia domanda: stavo chiedendo delloperatore AND, il che significa che il file è un risultato positivo solo se corrisponde al pattern A e al pattern B e pattern C e … AND Nel tuo caso il file è positivo se ma tches pattern A o pattern B o … Vedi la differenza ora?
  • @greenoldman non è sicuro del motivo per cui pensi che questo ciclo non controlli la condizione AND per tutti i pattern? Quindi ‘ ho modificato la mia risposta con un esempio reale: cercherà nel file tutte le espressioni regolari della lista, e sulla prima che manca – uscirà con errore.
  • Ce lhai davanti ai tuoi occhi, hai una corrispondenza positiva subito dopo lesecuzione della prima corrispondenza. Dovresti avere ” raccogliere ” tutti i risultati e calcolare AND su di essi. Quindi dovresti riscrivere lo script per eseguirlo su più file, quindi forse ti rendi conto che la domanda ha già una risposta e il tuo tentativo non porta nulla al tavolo, scusa.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *