2009-03-05 5 views
11

All'interno di una directory, come posso eliminare i file che non contengono le parole specificate, in modo che siano rimasti solo i file che contengono TUTTE le parole? Ho provato a scrivere un semplice script di shell bash usando i comandi grep e rm, ma mi sono perso. Sono totalmente nuovo per Linux, tutto l'aiuto sarebbe apprezzatoLinux: rimozione di file che non contengono tutte le parole specificate

risposta

20

Come su:

grep -L foo *.txt | xargs rm 
grep -L bar *.txt | xargs rm 

Se un file è non contiene foo, quindi la prima riga verrà rimossa ve.

Se un file non non contengono bar, poi la seconda linea sarà rimuoverlo.

solo i file che contengono sia foo e bar dovrebbero essere lasciati

-L, --files-without-match 
    Suppress normal output; instead print the name of each input 
    file from which no output would normally have been printed. The 
    scanning will stop on the first match. 

Vedi anche @Mykola Golubyev's post per l'immissione in un ciclo.

+0

penso che i file con foo OR bar, verranno eliminati con questo. – claf

+0

No - L nega il grep. – toolkit

+0

@toolkit: oups, my bad. – claf

0

In primo luogo, rimuovere il filelist:

rm flist 

Poi, per ciascuna delle parole, aggiungere il file al filelist se contiene quella parola :

grep -l WORD * >>flist 

quindi ordinare, uniqify e ottenere un conteggio:

sort flist | uniq -c >flist_with_count 

tutti quei file in flsi t_with_count che non ha il numero di parole dovrebbe essere cancellato. Il formato sarà:

2 file1 
7 file2 
8 file3 
8 file4 

Se c'erano 8 parole, quindi file1 e file2 devono essere eliminati. Lascerò la scrittura/test della sceneggiatura a te.

Ok, mi hai convinto, ecco il mio script:

#!/bin/bash 
rm -rf flist 
for word in fopen fclose main ; do 
    grep -l ${word} *.c >>flist 
done 
rm $(sort flist | uniq -c | awk '$1 != 3 {print $2} {}') 

Questo rimuove i file nella directory che non hanno tutte le tre parole:

-2

Questo consente di eliminare tutti i file che non contenga parole Ping o inviati

grep -L 'Ping\|Sent' * | xargs rm 
+0

Ciò non rimuoverà i file che contengono solo una delle parole. –

+0

Sì, l'ho già notato e ho premuto delete, ma era troppo tardi. –

11
list=`Word1 Word2 Word3 Word4 Word5` 
for word in $list 
    grep -L $word *.txt | xargs rm 
done 
5

aggiunta alle risposte di cui sopra: utilizzare il carattere di nuova riga come delimitatore di gestire i nomi di file con spazi !

grep -L $word $file | xargs -d '\n' rm 
1

a fare lo stesso nome di file corrispondenti (non il contenuto dei file come la maggior parte delle soluzioni di cui sopra) è possibile utilizzare il seguente:

for file in `ls --color=never | grep -ve "\(foo\|bar\)"` 
do 
    rm $file 
done 

Come per i commenti:

for file in `ls` 

shouldn essere usato Il sotto fa la stessa cosa senza utilizzare il ls

for file in * 
do 
    if [ x`echo $file | grep -ve "\(test1\|test3\)"` == x ]; then 
    rm $file 
    fi 
done 

La ve inverte la ricerca del modello regexp sia per foo o la barra nel nome del file. Eventuali ulteriori parole da aggiungere all'elenco devono essere separate da \ | ad es. uno \ | due \ | tre

+0

Il file in "ls" è una cattiva idea. – porges

+0

Buon punto. Modificato di conseguenza, ma non mi piace come questo lo complichi. Riesci a pensare a un modo più efficiente? – Andy

0

Si potrebbe provare qualcosa di simile, ma si può rompere se i modelli contengono guscio o grep meta caratteri:

(in questo esempio uno due tre sono i modelli)

for f in *; do 
    unset cmd 
    for p in one two three; do 
    cmd="fgrep \"$p\" \"$f\" && $cmd" 
    done 
    eval "$cmd" >/dev/null || rm "$f" 
done