Bagaimana cara mencari string dalam file PHP menggunakan `grep`?

11

Saya mencari deklarasi kelas di situs dengan ratusan file PHP. Bagaimana saya bisa melakukan ini di folder saat ini dan subfolder menggunakan grep ?

Saya menguji cdke folder dan kemudian sesuatu seperti

grep -r 'class MyClass' *.php
Peter Mortensen
sumber
Ketika ini bermigrasi ke pengguna super, Anda mungkin ingin mengatakan sesuatu tentang apa yang Anda inginkan yang grep -rtidak memberi Anda.
Saya bingung - bukankah Anda hanya menjawab sendiri? apa hasil dari garis itu? apakah Anda mencoba untuk lebih mengoptimalkannya? harap bayangkan membaca pertanyaan ini sebagai orang lain, karena membingungkan dan tidak jelas.
meder omuraliev
@ komentar lain: Pernyataan grep -rnya tidak memberikan apa yang diinginkannya, kecuali semua folder diakhiri dengan .php yang mungkin bukan itu masalahnya ...
David Oneill
Saya tidak mendapatkan apa-apa sama sekali. Saya menganggap itu tidak berhasil karena saya tahu itu menemukannya ketika saya pada folder yang memiliki file dengan kelas ini
Saya menemukan file itu karena keberuntungan. Saat mencari file di folder yang memiliki file PHP dengan baris itu, ia menemukannya (tidak perlu -r). Jika saya CD ke root dan melakukan pencarian dengan rekursi -r itu tidak mengembalikan apa pun.

Jawaban:

24

Anda dapat mencoba

grep -r --include=*.php "search string" /path/to/dir
rahul286
sumber
1
Bagus sekali. Saya terus lupa, tapi untungnya selalu ada jawaban ini lagi untuk membantu saya. :)
GolezTrol
@GolezTrol Senang mengetahui bahwa :-)
rahul286
9

Saya sarankan Anda menggunakan sesuatu seperti ctag daripada melakukannya dengan grep. Namun, jika Anda mau, Anda bisa melakukan sesuatu seperti

 find <top level dir> -name \*.php | xargs grep "class MyClass"

Ini tentu saja mengasumsikan bahwa Anda hanya memiliki satu ruang di antara classdan myClassyang mungkin tidak benar. Sangat mudah untuk mengubah regexp untuk mencari sejumlah spasi putih.

Noufal Ibrahim
sumber
4

Jika Anda menggunakan -r, Anda mungkin ingin secara rekursif mencari hanya direktori saat ini :

grep -r 'class MyClass' .

Perhatikan periode pada akhir di atas.

Apa yang Anda katakan grepadalah bahwa Anda ingin mencari secara rekursif setiap *.phpfile atau direktori , tetapi Anda kemungkinan tidak memiliki direktori yang berakhir dengan ekstensi .php. Di atas adalah cara termudah untuk melakukan pencarian tetapi juga termasuk file dari jenis lain yang sangat bermasalah ketika Anda memiliki direktori .svn di mana-mana. Jika Anda tidak memiliki banyak jenis file lain, yang di atas umumnya cukup dan berfungsi dengan baik.

Sebagian besar inkarnasi grep tidak memiliki cara untuk menentukan ekstensi file yang dapat dicari, jadi Anda biasanya menggunakan find bersama dengan itu:

find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} \;

-inamememberi tahu beberapa versi grep bahwa Anda ingin melakukan pencarian nama file case-insensitive, tetapi banyak varian non GNU find tidak mendukungnya, jadi Anda bisa menggunakannya -name.

The -execopsi di atas memiliki efek samping menyerukan grep untuk setiap file, yang cukup mahal.

Masih ada versi lain dari dukungan grep +yang memberitahu find untuk menambahkan argumen bersama-sama untuk mengurangi jumlah doa yang dapat dieksekusi:

find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} + \;

Cara yang sering disarankan untuk mengurangi doa adalah menggunakan xargs yang akan mengaktifkan grep sesering mungkin tetapi sesering yang diperlukan:

find <startDir> -iname \*.php | xargs grep "class[ \t]*MyClass"

xargscukup cerdas untuk meneruskan grep hingga jumlah maksimum argumen yang didukung pada baris perintah, tetapi variasi di atas tidak menangani karakter tertentu seperti spasi dengan sangat baik. Sebagai contoh, adalah 'file.php' nama file grep akan menerima 'the' sebagai argumen dan 'file.php' sebagai argumen sehingga keduanya tidak akan ditemukan. Sebaliknya, kami menggunakan:

find <startDir> -iname \*.php -print0 | xargs -0 grep "class[ \t]*MyClass"

print0dan -0bekerja bersama dan menggunakan argumen yang diikuti oleh karakter nol sehingga argumen tersebut sepenuhnya dan tidak ambigu diidentifikasi.

Jika Anda memiliki lebih dari satu spasi setelahnya class, atau tab, Anda mungkin ingin mengizinkan lebih banyak karakter dengan mengubah regex:class[ \t]*MyClass

Posting di StackOverflow ini memiliki contoh lain dan menunjukkan cara mengecualikan direktori tertentu, seperti direktori .svn.

Kaleb Pederson
sumber
Ini mencari semua file. Juga file yang bukan file .php.
GolezTrol
Saya telah memperbarui posting untuk memasukkan banyak contoh lainnya.
Kaleb Pederson
3

Menggunakan ack yang selalu indah ,

ack --php 'class MyClass'
singkat
sumber
1
grep -r 'class MyClass' *.php

akan mencari melalui semua folder dengan nama yang diakhiri dengan .php

grep -r 'class MyClass' . | grep .php

akan mencari kelas MyClass di semua file di semua sub folder, kemudian hanya mengembalikan yang memiliki .php di dalamnya.

David Oneill
sumber
1

find . -type f -name *.php -print -exec grep \"class MyClass\" {} \; akan memberi Anda konten dari garis yang ditemukannya serta jalur ke file.

prodigitalson
sumber
1

Jika file yang cocok mungkin memiliki nama yang berubah-ubah, Anda harus mempertimbangkan untuk menggunakannya -print0

Temukan . -type f -name '* .php' -print0 | xargs -0 grep 'class MyClass'

wudeng
sumber
1
grep -rl 'class MyClass' . --include \*.php

Saya hanya menunjukkan nama file

r adalah rekursif

. mencari di folder saat ini

--sertakan batas ekstensi nama file

Penuh
sumber
1

Mungkin Anda menginginkan ketidakpekaan huruf dan toleransi spasi, dan grep akan berhenti jika tidak menemukan contoh pola file yang diinginkan dalam direktori saat ini. Perlu tahu di mana untuk memulai, seolah-olah, dan tidak ada file yang cocok tidak menghasilkan jalur awal.

Jika setidaknya ada satu file dari ekstensi yang diinginkan, maka Anda dapat menggunakan egrep -ir. finddan xargstunjukkan kekuatan mereka dengan direktori flat (tapi sangat besar) tunggal yang gagal gagal dan kualifikasi tambahan (misalnya jika Anda ingin mencari file .inc, .php, dan php3 saja). Tapi itu kehilangan sedikit kenyamanan dan kecepatan dalam pengalaman saya. Untuk deklarasi kelas tertulis manusia masalah besar akan menjadi spasi. Jadi gunakan egrep bukan grep. LC_ALL = C juga untuk kecepatan ekstra. Untuk kenyamanan, saya sering menggunakan:

LC_ALL=C egrep -irn "class[ ]*myclass([ ]|\n)" * | egrep "\.(inc|php[35]?)"

-i -- case insensitive
-r -- recursive for all file pattern (here *)
-n -- include the line number
LC_ALL=C -- search in ASCII, not in utf8, this is much faster.

[ ]* -- match any number of spaces before the class name
([ ]|\n) -- match a space or newline after the classname

Ini masih dapat mencocokkan komentar, seperti // class myclass exists in file, tetapi saya menemukan itu relatif kecil, dan mereka dapat disaring... | fgrep -v '//'

Anda juga dapat menyertakan topeng file yang lebih kompleks (misalnya, untuk menangkap sebagian besar file .inc dan .php) pada pola file egrep seperti:

egrep "pattern" *.[ip]*

Itu (dengan opsi pertama) akan sangat cepat dan sebagian besar terbatas pada file php.

HTH

Beracah
sumber
0

Aku tahu itu mengatakan menggunakan grep, tapi favorit pribadi saya adalah untuk digunakan ack-grep:

ack-grep "class MyClass"

Ini berjalan secara rekursif, daftar nama file yang ditemukan hasilnya, dengan nomor baris untuk tempat mereka ditemukan, dan highlight. Untuk secara khusus menargetkan file php Anda dapat menjalankan:

ack-grep --type-set php:ext:php "path"

Paket ini memiliki banyak pilihan; Saya pasti akan merekomendasikannya (dan menelusuri halaman man terkait) untuk melakukan hal-hal mewah.

jhaagsma
sumber