Commenti
- Cosa intendi di " lintera parte di ogni stringa "? ' non vuoi che lintera riga venga stampata?
- Potresti confermare che desideri che i file corrispondenti contengano entrambi " foo " e " 321 " ma non solo " foo " o semplicemente " 321 "?
- Mi piace come è ' s
321
invece dibar
: – D
Risposta
GNU grep
Dovrebbe essere un po più veloce perché il secondo grep
può operare su un elenco di file.
grep -lZ "foo" * | xargs -0 grep -l "321"
POSIX grep con find
find
è più utile se desideri cercare directory ricorsive (in tal caso, perdi -mindepth
e -maxdepth
opzioni.
find . -mindepth 1 -maxdepth 1 -type f -exec grep -q "foo" {} \; -exec grep -l "321" {} +
Commenti
Answer
Puoi farlo con un breve script:
for FILE in * do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE done
Puoi farlo anche su una riga:
for FILE in *; do grep -q foo $FILE && grep -q 321 $FILE && echo $FILE; done
grep
restituisce 0 (true) se ha trovato la stringa e &&
che separa i comandi significa che il secondo verrà eseguito solo se il primo era vero. Lopzione -q
assicura che grep
non restituisca nulla.
Leco verrà eseguito solo se entrambe le stringhe sono trovato nello stesso file.
Ho pensato a un modo diverso per farlo. In questo modo sarà probabilmente più efficiente se i file in questione sono più grandi della RAM installata poiché è sufficiente grep
attraverso ogni file una volta.
for FILE in * do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE done
e la versione a una riga:
for FILE in *; do test $(egrep -o "foo|321" $FILE | uniq | sort | uniq | wc -l) -eq 2 && echo $FILE; done
Commenti
- Per una soluzione più efficiente: cosa succede se il file contiene " foo foo "?
- Quello ' s a cosa serve
uniq | sort | uniq
. " foo foo " finisce per essere una riga ma " foo 321 " finisce per essere due righe perchégrep -o
restituisce tutte le stringhe trovate su righe separate, anche se iniziano sulla stessa riga. - Se i file diventano così grandi che sarebbe OK eseguire il fork almeno sei volte per file, allora probabilmente ha senso usare awk in modo che i file non debbano essere cercati fino alla fine.
- @Ladadadada ha ottenuto esso. 🙂
- @HaukeLaging
grep -q
egrep -l
non cerca fino alla fine del file: escono non appena quando viene trovata una corrispondenza. Mi chiedo perché la prima soluzione non sia ' tfor FILE in *; do grep -q foo "$FILE" && grep -l 321 "$FILE"; done
Risposta
Strano. Per me entrambe le varianti funzionano (grep (GNU grep) 2.13):
grep "foo\|321" grep -E "foo|321"
Modifica 1 – mostra solo i file con entrambe le corrispondenze
La risposta for file in *
funziona ma può diventare un incubo per le prestazioni (per grandi quantità di file ): almeno due processi per file. Questo è più veloce (nel mondo GNU):
find . -type f -print0 | xargs -0 -r grep --files-with-matches --null -- string1 | xargs -0 -r grep --files-with-matches -- string2
stringa1 dovrebbe essere quella che risulta in meno corrispondenze.
Commenti
- Il richiedente sta cercando che il risultato restituisca true solo se un file contiene entrambe le stringhe piuttosto che se ne corrisponde solo ad almeno una.
- Mi piace Opzione
--files-with-matches
. Basta leggerlo nella pagina man e fa sì che grep si fermi dopo aver trovato la prima corrispondenza, il che significa che ' è molto efficiente per file di grandi dimensioni se la corrispondenza avviene in anticipo. Dice anche che lopzione breve-l
è specificata da POSIX, quindi può essere utilizzata al di fuori del mondo GNU. - @Ladadadada Lefficienza non è un vantaggio rispetto al tuo -q, però. Menzionando GNU non stavo ' pensando a –files-with-match ma a -0 / –null.Quello che mi viene in mente: lespansione del nome del percorso contiene un ordinamento alfabetico (davvero pessimo: sembra che ' non possa nemmeno essere disattivato) quindi per enormi quantità di file anche il tuo
for file in *
smette di essere davvero divertente. - In effetti, le ottimizzazioni dellefficienza sarebbero molto diverse per pochi file di grandi dimensioni rispetto a molti piccoli e
*
solo ' non funzionerà affatto dopo poche migliaia di file. - @Ladadadada Non ' t funziona come parte di una riga di comando per un comando esterno:
grep foo *
Mafor file in *
è una struttura interna alla shell quindi presumo che il limite della riga di comando non è applicabile qui.
Answer
Fondamentalmente, per trovare tutti i file incluso un particolare stringa in una directory, puoi utilizzare:
grep -lir "pattern" /path/to/the/dir
-
-l
: per eseguire questa scansione si fermerà alla prima corrispondenza -
-i
: per ignorare la distinzione tra maiuscole e minuscole sia nel modello che nei file di input -
-r
: cerca in tutti i file nella directory, ricorsivamente
Per cercare due modelli, prova questo:
grep -lr "321" $(grep -lr "foo" /path/to/the/dir)
Commenti
- Commenti noiosi standard su
$()
che non gestisce bene gli spazi si applicano. In pratica per una riga nella shell questo comando funzionerà bene.
Risposta
Dovrebbe essere
grep -e "foo" -e "321" *
Usa -e per più pattern
EDIT
Nel caso in cui sia necessario che entrambi corrispondano:
grep -e ".*foo.*321.*" *
Se lordine non ha importanza:
grep -e ".*foo.*321.*" ".*321.*foo.*" *
Commenti
- Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti a un autore, lascia un commento sotto il suo post.
- @mdpc penso che fornisca una risposta. Cosa ti fa pensare in modo diverso?
- @HaukeLaging Perché restituisce se uno dei due pattern corrisponde. LOP sta cercando un caso in cui restituisce vero solo se entrambi si trovano nel file.
- A quanto mi risulta, trova solo file in cui entrambe le stringhe contengono sulla stessa riga (I don ' t pensare. corrisponde a nuove righe per impostazione predefinita)
-r
ha funzionato bene sul primogrep
per rendere quella soluzione GNU ricorsiva per me, invece di utilizzare la riga POSIX con tutti questiexec
s