Come trovo i file che non contengono un determinato modello di stringa?


Risposte:


818

Se il tuo grep ha l' opzione -L(o --files-without-match):

$ grep -L "foo" *

1
Come sottolineato altrove, ack aiuta a evitare i file .svn (sovversione) per impostazione predefinita.
GuruM,

11
@GuruM Questo può essere fatto in GNU grep esportando la variabile GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git': ^)
bufh

6
O l'equivalente usando ag :ag -L 'foo'
vescovo

5
Funziona come per magia! Suggerimento: utilizzare -rLinvece di -Labbinare le sottodirectory
Ufo

1
@Larry - Un modo più pulito per evitare problemi di globbing è usare l'opzione lunga "vuota" come questa: grep -L 'foo' -- *lo standard è che i comandi che richiedono opzioni lunghe usano --per indicare che non ci sono più opzioni dopo questo punto.
Paddy Landau,

45

Dai un'occhiata ack. Fa .svnautomaticamente l' esclusione per te, ti dà espressioni regolari Perl ed è un semplice download di un singolo programma Perl.

L'equivalente di ciò che stai cercando dovrebbe essere, in ack:

ack -L foo

24

Puoi farlo con grep da solo (senza trovare).

grep -riL "foo" .

Questa è la spiegazione dei parametri utilizzati su grep

     -L, --files-without-match
             each file processed.
     -R, -r, --recursive
             Recursively search subdirectories listed.

     -i, --ignore-case
             Perform case insensitive matching.

Se usi l(maiuscolo) otterrai il contrario (file con corrispondenze)

     -l, --files-with-matches
             Only the names of files containing selected lines are written

17

Il seguente comando mi dà tutti i file che non contengono il modello foo:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep 0

4
Si desidera modificare grep 0 alla fine in grep 0 $ (altrimenti si ottengono corrispondenze errate sui file che hanno il carattere 0 nel loro nome file).
Clouseau,

9
@clouseau ha principalmente ragione ... Tuttavia, grep '0$'corrisponderebbe anche ai file con multipli di 10 righe! È necessario grep ':0$'al fine di verificare la presenza di un esplicito ': 0' alla fine della linea. Quindi otterrai solo file con zero righe corrispondenti.
TrinitronX

L'UNIX su cui mi trovo non aveva versioni di find o grep con queste opzioni, quindi ho dovuto seguire il comando "ack" suggerito in altri commenti.
KC Baltz,

14

Il seguente comando esclude la necessità che find trovi il filtro delle svncartelle usando un secondo grep.

grep -rL "foo" ./* | grep -v "\.svn"

9

Avrai effettivamente bisogno di:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep :0\$

6

Ho avuto fortuna con

grep -H -E -o -c "foo" */*/*.ext | grep ext:0

I miei tentativi con grep -vappena mi hanno dato tutte le linee senza "pippo".


4

Problema

Ho bisogno di refactoring di un grande progetto che utilizza i .phtmlfile per scrivere HTML usando il codice PHP in linea. Voglio usare invece i modelli Moustache . Voglio trovare eventuali .phtmlfile che non contengano la stringa new Mustachepoiché devono ancora essere riscritte.

Soluzione

find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

Spiegazione

Prima dei tubi:

Trova

find . Trova i file in modo ricorsivo, iniziando da questa directory

-iname '*.phtml'Il nome file deve contenere .phtml(non lo idistingue tra maiuscole e minuscole)

-exec 'grep -H -E -o -c 'new Mustache' {}'Esegui il grepcomando su ciascuno dei percorsi corrispondenti

grep

-H Stampa sempre le intestazioni del nome file con le righe di output.

-E Interpreta il pattern come un'espressione regolare estesa (ovvero forza grep a comportarsi come egrep).

-o Stampa solo la parte corrispondente delle linee.

-c Solo un conteggio delle righe selezionate viene scritto nell'output standard.


Questo mi darà un elenco di tutti i percorsi dei file che finiscono .phtml, con un conteggio del numero di volte in cui la stringa si new Mustacheverifica in ciascuno di essi.

$> find . -iname '*.phtml$' -exec 'grep -H -E -o -c 'new Mustache' {}'\;

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/orders.phtml:1
./app/MyApp/Customer/View/Account/banking.phtml:1
./app/MyApp/Customer/View/Account/applycomplete.phtml:1
./app/MyApp/Customer/View/Account/catalogue.phtml:1
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

La prima pipe grep :0$filtra questo elenco per includere solo le righe che terminano in :0:

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml:0
./app/MyApp/Customer/View/Account/studio.phtml:0
./app/MyApp/Customer/View/Account/classadd.phtml:0
./app/MyApp/Customer/View/Account/orders-trade.phtml:0

La seconda pipe sed 's/..$//'rimuove gli ultimi due caratteri di ogni riga, lasciando solo i percorsi dei file.

$> find . -iname '*.phtml' -exec grep -H -E -o -c 'new Mustache' {} \; | grep :0$ | sed 's/..$//'

./app/MyApp/Customer/View/Account/quickcodemanagestore.phtml
./app/MyApp/Customer/View/Account/studio.phtml
./app/MyApp/Customer/View/Account/classadd.phtml
./app/MyApp/Customer/View/Account/orders-trade.phtml

3

Se stai usando git, questo cerca tutti i file tracciati:

git grep -L "foo"

e puoi cercare in un sottoinsieme di file tracciati se hai attivato il ** globbing nella sottodirectory ( shopt -s globstarin .bashrc, vedi questo ):

git grep -L "foo" -- **/*.cpp

1

Il mio grep non ha alcuna opzione -L. Trovo soluzioni alternative per raggiungere questo obiettivo.

Le idee sono:

  1. per scaricare tutto il nome del file contenente la stringa meritata in un txt1.txt.
  2. scaricare tutto il nome del file nella directory su un txt2.txt.
  3. fare la differenza tra il file di dump 2 con il comando diff.

    grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
    grep * *.log | cut -c1-14 | uniq > txt2.txt
    diff txt1.txt txt2.txt | grep ">"
    

Ho dimenticato i comandi ma invece di scaricare i nomi dei file, puoi effettivamente fare difftra due flussi di output (penso che tu circonda i comandi tra parentesi e c'è anche una parentesi angolare da qualche parte), se i tuoi sistemi lo supportano, che immagino è la domanda, poiché non supportagrep -L
Dexygen

1

find *20161109* -mtime -2|grep -vwE "(TRIGGER)"

È possibile specificare il filtro in "trova" e la stringa di esclusione in "grep -vwE". Usa mtime sotto find se hai bisogno di filtrare anche sul tempo modificato.


Questo sembra mostrarmi tutte le linee senza la stringa, l'OP chiede solo i nomi dei file.
Ben Farmer,

1

Apri segnalazione bug

Come commentato da @tukan, esiste una segnalazione di bug aperta per Ag riguardante il flag -L/ --files-without-matches:

Poiché la segnalazione del bug presenta pochi progressi, l' -Lopzione menzionata di seguito non deve essere considerata attendibile , non finché il bug non è stato risolto. Utilizzare invece approcci diversi presentati in questo thread. Citando un commento per la segnalazione di bug [mio accento]:

Qualche aggiornamento su questo? -Lignora completamente le corrispondenze sulla prima riga del file. Sembra che se questo non verrà risolto presto, la bandiera dovrebbe essere rimossa del tutto, poiché effettivamente non funziona come pubblicizzato .


Silver Searcher - Ag (funzione prevista - vedere la segnalazione di bug)

Come potente alternativa a grep, è possibile utilizzare The Silver Searcher - Ag :

Uno strumento di ricerca del codice simile a ack, con un focus sulla velocità.

Guardando man ag, troviamo l' opzione -Lo --files-without-matches:

...

OPTIONS
    ...

    -L --files-without-matches
           Only print the names of files that don´t contain matches.

Vale a dire, per cercare ricorsivamente file che non corrispondono foo, dalla directory corrente:

ag -L foo

Per cercare solo nella directory corrente i file che non corrispondono foo, basta specificare --depth=0per la ricorsione:

ag -L foo --depth 0

Ciò non riesce di tanto in tanto a causa del -Lbug - github.com/ggreer/the_silver_searcher/issues/238
tukan

@tukan grazie per la richiesta. Ho aggiornato la risposta; scegliendo di non cancellare la risposta ma aprendosi invece con le informazioni relative al bug.
dri

1

un'altra alternativa quando grep non ha l'opzione -L (ad esempio IBM AIX), con nient'altro che grep e la shell:

for file in * ; do grep -q 'my_pattern' $file || echo $file ; done

-4
grep -irnw "filepath" -ve "pattern"

o

grep -ve "pattern" < file

sopra il comando ci darà il risultato come -v trova l'inverso del pattern cercato


1
Ciò stampa le linee che non contengono il motivo. È possibile aggiungere l' -lopzione per stampare solo il nome del file; ma ciò stampa ancora i nomi di qualsiasi file che contiene una riga che non contiene il modello. Credo che l'OP voglia trovare i file che non contengono alcuna riga che contiene il modello.
triplo il

Il comando che hai fornito elenca i file in "percorso file" con tutte le loro linee che non contengono "modello".
aprodan,

-6

Il seguente comando potrebbe aiutarti a filtrare le linee che includono la sottostringa "pippo".

cat file | grep -v "foo"

2
Stampa le linee che non corrispondono, non i nomi dei file che non contengono una corrispondenza su nessuna riga. Per aggiungere la beffa al danno, è un uso inutile dicat .
triplo il
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.