Grep cerca due parole in una riga


46

Ho cercato di trovare un modo per filtrare una riga che contiene la parola "limone" e "riso". So come trovare "limone" o "riso", ma non i due. Non hanno bisogno di essere vicini all'altro, solo uno della stessa riga di testo.


1
Per trovare tutte le stringhe all'interno di un file, puoi eseguire grep nel ciclo FOR: unix.stackexchange.com/a/462445/43233
Noam Manos

Risposte:


62

"Entrambi sulla stessa linea" significa "riso" seguito da caratteri casuali seguiti da "limone" o viceversa ".

In regex che è rice.*lemono lemon.*rice. Puoi combinarlo usando un |:

grep -E 'rice.*lemon|lemon.*rice' some_file

Se si desidera utilizzare regex normale anziché quelli estesi ( -E) è necessario una barra rovesciata prima di |:

grep 'rice.*lemon\|lemon.*rice' some_file

Per altre parole che diventano rapidamente un po 'lunghe ed è generalmente più facile usare più chiamate di grep, ad esempio:

grep rice some_file | grep lemon | grep chicken

La tua ultima riga è una congiunzione non disgiunzione no? Vale a dire: le grep ricelinee di ricerca contenenti rice. È alimentato in grep lemoncui troverà solo righe contenenti limone .. e così via. Considerando che il PO - così come le tue precedenti risposte - stanno permettendo uno qualsiasi di [riso | limone | pollo]
javadba

Versione script: askubuntu.com/a/879253/5696
Jeff

@Florian Diesch - Ti dispiace spiegare perché |bisogna evadere grep? Grazie!
fuggitivo

1
@fugitive egrepusa regex esteso dove |è inteso come logica OR. grepper impostazione predefinita regex di base, dove si \|trova OR
Sergiy Kolodyazhnyy

Come indicato nella grepmanpage di, egrepè obsoleto e deve essere sostituito da grep -E. Mi sono preso la libertà di modificare la risposta di conseguenza.
Dessert,

26

È possibile reindirizzare l'output del primo comando grep a un altro comando grep e questo corrisponderebbe a entrambi i modelli. Quindi, puoi fare qualcosa del tipo:

grep <first_pattern> <file_name> | grep <second_pattern>

o,

cat <file_name> | grep <first_pattern> | grep <second_pattern>

Esempio:

Aggiungiamo alcuni contenuti al nostro file:

$ echo "This line contains lemon." > test_grep.txt
$ echo "This line contains rice." >> test_grep.txt
$ echo "This line contains both lemon and rice." >> test_grep.txt
$ echo "This line doesn't contain any of them." >> test_grep.txt
$ echo "This line also contains both rice and lemon." >> test_grep.txt

Cosa contiene il file:

$ cat test_grep.txt 
This line contains lemon.
This line contains rice.
This line contains both lemon and rice.
This line doesn't contain any of them.
This line also contains both rice and lemon.

Ora, grep quello che vogliamo:

$ grep rice test_grep.txt | grep lemon
This line contains both lemon and rice.
This line also contains both rice and lemon.

Otteniamo solo le linee in cui entrambi i modelli corrispondono. Puoi estenderlo e reindirizzare l'output a un altro comando grep per ulteriori corrispondenze "AND".


21

Sebbene la domanda richieda "grep", ho pensato che potesse essere utile pubblicare una semplice soluzione "awk":

awk '/lemon/ && /rice/'

Questo può essere facilmente esteso con più parole o altre espressioni booleane oltre a "e".


11

Un'altra idea per trovare le partite in qualsiasi ordine sta usando:

grep con l' opzione -P (Compatibilità Perl) e regex lookahead positivo(?=(regex)) :

grep -P '(?=.*?lemon)(?=.*?rice)' infile

oppure puoi usare qui sotto, invece:

grep -P '(?=.*?rice)(?=.*?lemon)' infile
  • I .*?mezzi di riscontro caratteri .che gli eventi da zero o più volte *, mentre sono opzionali seguiti da un modello ( riceo lemon). La ?rende tutto facoltativa prima che (mezzi zero o una volta di tutto abbinato .*)

(?=pattern): Lookahead positivo: il costrutto lookahead positivo è una coppia di parentesi, con la parentesi aperta seguita da un punto interrogativo e un segno di uguale.

Quindi questo restituirà tutte le righe con contiene entrambi lemone ricein ordine casuale. Anche questo eviterà di usare se |raddoppiato grep.


Collegamenti esterni: Argomenti avanzati di Grep Lookahead positivo - GREP for Designers


5
grep -e foo -e goo

Restituirà le partite per foo o goo


1

Se ammettiamo che grepè accettabile fornire una risposta che non è basata, come la risposta di cui sopra awk, proporrei una perllinea semplice come:

$ perl -ne 'print if /lemon/ and /rice/' my_text_file

La ricerca può ignorare il caso con alcune / tutte le parole come /lemon/i and /rice/i. Sulla maggior parte delle macchine Unix / Linux, perl è installato e comunque awk.


Rifiutato !!! ;) Perché non ha senso .. :)
An0n

0

Ecco uno script per automatizzare la soluzione di piping grep:

#!/bin/bash

# Use filename if provided as environment variable, or "foo" as default
filename=${filename-foo}

grepand () {
# disable word splitting and globbing
IFS=
set -f
if [[ -n $1 ]]
then
grep -i "$1" ${filename} | filename="" grepand "${@:2}"
else
# If there are no arguments, assume last command in pipe and print everything
cat
fi
}

grepand "$@"

1
Questo dovrebbe probabilmente essere implementato usando una funzione ricorsiva, invece di costruire una stringa di comando e evalinserirla, che si interrompe facilmente
muru

@muru Sentiti libero di suggerire una modifica. Apprezzo il commento.
Jeff

1
Modificarlo sarà troppo riscrivibile, quindi non lo farò. Se vuoi aggiungerlo, ecco come immagino dovrebbe apparire: paste.ubuntu.com/23915379
muru,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.