Bagaimana cara menemukan file yang tidak berisi pola string yang diberikan?

536

Bagaimana cara mengetahui file dalam direktori saat ini yang tidak mengandung kata foo(menggunakan grep)?

Senthil Kumar
sumber

Jawaban:

818

Jika grep Anda memiliki opsi -L(atau --files-without-match):

$ grep -L "foo" *
ghostdog74
sumber
1
Seperti yang ditunjukkan di tempat lain ack membantu menghindari file .svn (subversi) secara default.
GuruM
11
@GuruM Ini bisa dilakukan dalam GNU grep dengan mengekspor variabel GREP_OPTIONS='--exclude-dir=.svn --exclude-dir=.git': ^)
bufh
6
Atau yang setara menggunakan ag :ag -L 'foo'
uskup
5
Bekerja seperti sulap! Petunjuk: gunakan -rLalih-alih -Luntuk mencocokkan subdirektori
Ufos
1
@Larry - Cara yang lebih bersih untuk menghindari masalah globbing adalah dengan menggunakan opsi "kosong" panjang seperti ini: Standarnya grep -L 'foo' -- *adalah bahwa perintah yang mengambil opsi lama gunakan --untuk menunjukkan bahwa tidak ada opsi lagi setelah titik ini.
Paddy Landau
45

Lihatlah ack. Itu .svnpengecualian untuk Anda secara otomatis, memberi Anda ekspresi reguler Perl, dan merupakan unduhan sederhana dari satu program Perl.

Setara dengan apa yang Anda cari seharusnya, di ack:

ack -L foo
Andy Lester
sumber
24

Anda dapat melakukannya dengan grep saja (tanpa menemukan).

grep -riL "foo" .

Ini adalah penjelasan tentang parameter yang digunakan grep

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

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

Jika Anda menggunakan l(huruf kecil) Anda akan mendapatkan yang sebaliknya (file dengan kecocokan)

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

Perintah berikut memberi saya semua file yang tidak mengandung pola foo:

find .  -not  -ipath '.*svn*' -exec  grep  -H -E -o -c  "foo"  {} \; | grep 0
Senthil Kumar
sumber
4
Anda ingin mengubah grep 0 di akhir menjadi grep 0 $ (jika tidak Anda mendapatkan kecocokan yang salah pada file yang memiliki karakter 0 dalam nama file mereka).
clouseau
9
@clouseau sebagian besar benar ... Namun, grep '0$'akan cocok dengan file dengan kelipatan 10 baris juga! Anda harus grep ':0$'di akhir untuk memeriksa ': 0' secara eksplisit di akhir baris. Maka Anda hanya akan mendapatkan file dengan garis nol yang cocok.
TrinitronX
UNIX yang saya gunakan tidak memiliki versi find atau grep dengan opsi-opsi ini, jadi saya harus menggunakan perintah "ack" yang disarankan di komentar lain.
KC Baltz
14

Perintah berikut tidak termasuk kebutuhan untuk menemukan untuk menyaring svnfolder dengan menggunakan yang kedua grep.

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

Anda benar-benar membutuhkan:

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

Saya beruntung dengan

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

Upaya saya dengan grep -vhanya memberi saya semua baris tanpa "foo".

Johnny
sumber
4

Masalah

Saya perlu memperbaiki proyek besar yang menggunakan .phtmlfile untuk menulis HTML menggunakan kode PHP sebaris. Saya ingin menggunakan template Moustache sebagai gantinya. Saya ingin menemukan .phtmlgile yang tidak mengandung string new Mustachekarena ini masih perlu ditulis ulang.

Larutan

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

Penjelasan

Sebelum pipa:

Temukan

find . Temukan file secara rekursif, mulai dari direktori ini

-iname '*.phtml'Nama file harus mengandung .phtml(thei make case-insensitive)

-exec 'grep -H -E -o -c 'new Mustache' {}'Jalankan grepperintah di setiap jalur yang cocok

Grep

-H Selalu cetak header nama file dengan jalur output.

-E Menafsirkan pola sebagai ekspresi reguler yang diperluas (yaitu memaksa grep untuk berperilaku sebagai egrep).

-o Hanya mencetak bagian garis yang cocok.

-c Hanya hitungan baris yang dipilih ditulis ke output standar.


Ini akan memberi saya daftar semua jalur file yang diakhiri .phtml, dengan hitungan berapa kali string new Mustachemuncul di masing-masing jalur tersebut .

$> 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

Pipa pertama grep :0$menyaring daftar ini untuk hanya menyertakan garis yang diakhiri dengan :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

Pipa kedua sed 's/..$//'melepas dua karakter terakhir dari setiap baris, hanya menyisakan path 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
Kasar
sumber
3

Jika Anda menggunakan git, ini mencari semua file yang dilacak:

git grep -L "foo"

dan Anda dapat mencari di subset file yang dilacak jika Anda memiliki ** subdirektori globbing dihidupkan ( shopt -s globstardalam .bashrc, lihat ini ):

git grep -L "foo" -- **/*.cpp
Zak
sumber
1

Grep saya tidak memiliki opsi -L. Saya menemukan solusi untuk mencapai ini.

Gagasannya adalah:

  1. untuk membuang semua nama file yang berisi string yang layak ke txt1.txt.
  2. buang semua nama file di direktori ke txt2.txt.
  3. buat perbedaan antara 2 dump file dengan perintah diff.

    grep 'foo' *.log | cut -c1-14 | uniq > txt1.txt
    grep * *.log | cut -c1-14 | uniq > txt2.txt
    diff txt1.txt txt2.txt | grep ">"
    
pengguna6305682
sumber
Saya lupa perintah tetapi alih-alih membuang nama file, Anda sebenarnya dapat melakukan diffantara dua aliran output (saya pikir Anda mengelilingi perintah dengan tanda kurung, dan ada kurung sudut di suatu tempat juga), jika sistem Anda mendukungnya, yang saya kira adalah pertanyaannya, karena itu tidak mendukunggrep -L
Dexygen
1

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

Anda dapat menentukan filter di bawah "find" dan string pengecualian di bawah "grep -vwE". Gunakan mtime di bawah find jika Anda juga perlu memfilter waktu yang dimodifikasi.

zandeep
sumber
Tampaknya ini menunjukkan kepada saya semua baris tanpa string, OP hanya meminta nama file.
Ben Farmer
1

Buka laporan bug

Seperti yang dikomentari oleh @tukan, ada laporan bug terbuka untuk Ag mengenai -L/ --files-without-matchesflag:

Karena ada sedikit kemajuan pada laporan bug, -Lopsi yang disebutkan di bawah ini tidak boleh diandalkan , tidak selama bug belum diselesaikan. Gunakan pendekatan berbeda yang disajikan dalam utas ini sebagai gantinya. Mengutip komentar untuk laporan bug [penekanan milik saya]:

Adakah pembaruan tentang ini? -Lsama sekali mengabaikan kecocokan pada baris pertama file. Sepertinya jika ini tidak akan segera diperbaiki, bendera harus dihapus seluruhnya, karena secara efektif tidak berfungsi seperti yang diiklankan sama sekali .


The Silver Searcher - Ag (fungsi yang dituju - lihat laporan bug)

Sebagai alternatif yang kuat untuk grep, Anda bisa menggunakan The Silver Searcher - Ag :

Alat pencarian kode yang mirip dengan ack, dengan fokus pada kecepatan.

Melihat man ag, kami menemukan opsi -Latau --files-without-matches:

...

OPTIONS
    ...

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

Yakni, untuk mencari file yang tidak cocok secara rekursiffoo , dari direktori saat ini:

ag -L foo

Untuk hanya mencari direktori saat ini untuk file yang tidak cocok foo, cukup tentukan --depth=0untuk rekursi:

ag -L foo --depth 0
dfri
sumber
Ini gagal dari waktu ke waktu karena -Lbug - github.com/ggreer/the_silver_searcher/issues/238
tukan
@tukan terima kasih untuk promptnya. Saya telah memperbarui jawabannya; memilih untuk tidak menghapus jawaban tetapi membuka dengan info tentang bug.
dfri
1

alternatif lain ketika grep tidak memiliki opsi -L (misalnya IBM AIX), dengan grep dan shell:

for file in * ; do grep -q 'my_pattern' $file || echo $file ; done
JMD
sumber
-4
grep -irnw "filepath" -ve "pattern"

atau

grep -ve "pattern" < file

perintah di atas akan memberi kita hasilnya karena -v menemukan kebalikan dari pola yang dicari

Jay
sumber
1
Ini mencetak garis-garis yang tidak mengandung pola. Anda dapat menambahkan -lopsi untuk mencetak hanya nama file; tetapi ini masih mencetak nama-nama file yang berisi baris apa pun yang tidak mengandung pola. Saya percaya OP ingin menemukan file yang tidak mengandung garis apa pun yang berisi pola.
tripleee
Perintah Anda berikan daftar file dalam "filepath" dengan semua baris mereka yang tidak mengandung "pola".
aprodan
-6

Perintah berikut ini dapat membantu Anda untuk memfilter garis yang menyertakan "foo" substring.

cat file | grep -v "foo"
walkerlin
sumber
2
Ini mencetak baris yang tidak cocok, bukan nama file yang tidak mengandung kecocokan pada baris apa pun. Untuk menambah penghinaan pada cedera, itu sebagai penggunaan yang tidak bergunacat .
tripleee