Questa domanda ha già una risposta qui :

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 di bar: – 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

  • -r ha funzionato bene sul primo grep per rendere quella soluzione GNU ricorsiva per me, invece di utilizzare la riga POSIX con tutti questi exec s

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 e grep -l non cerca fino alla fine del file: escono non appena quando viene trovata una corrispondenza. Mi chiedo perché la prima soluzione non sia ' t for 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 * Ma for 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)

Lascia un commento

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