Apakah ada cara yang lebih sederhana untuk menangkap semua file di bawah direktori?


21

Ketika saya ingin mencari seluruh pohon untuk beberapa konten, saya menggunakan

find . -type f -print0 | xargs -0 grep <search_string>

Apakah ada cara yang lebih baik untuk melakukan ini dalam hal kinerja atau singkatnya?


2
@Downvoter: Senang untuk meningkatkan pertanyaan ini jika Anda dapat membagikan kekhawatiran Anda.
Dancrumb

2
banyak versi find memiliki xargs bawaan: find. -type f -exec fgrep <search_string> {} +
simpleuser

Jawaban:


42

Periksa apakah opsi grepdukungan Anda -r(untuk pengulangan ):

grep -r <search_string> .

1
Yup ... Saya baru saja menemukan stackoverflow.com/questions/16956810/… dan itulah jawabannya juga.
Dancrumb

tambahkan komentar tentang --exclude-diruntuk mengatasi kinerja dan kami memiliki seorang pemenang!
Dancrumb

1
Hanya perhatikan bahwa ini tidak portabel, tetapi greppada distro FreeBSD dan Linux terbaru mendukungnya. Dan mengapa --exclude-dir? Tidakkah Anda meminta untuk mencari seluruh pohon ?
Philippos

Titik adil ... --exclude-dirsebenarnya berguna dalam kasus penggunaan saya (karena bagian dari subtree besar, tetapi tidak berguna) dan saya memang bertanya tentang kinerja ... tetapi Anda benar, itu tidak perlu.
Dancrumb

Dalam hal ini saya harus menambahkan bahwa IIRC --exclude-direksklusif untuk GNU grep. (-:
Filipina

13

Jawaban sub optimal: Alih-alih menyalurkan output findke grep, Anda bisa menjalankan

find . -type f -exec grep 'research' {} '+'

dan voila, satu perintah, bukan dua!

penjelasan:

find . -type f

temukan semua file biasa di dalamnya.

-exec grep 'research'

grep 'penelitian'

{}

dalam nama file yang ditemukan

'+'

gunakan satu perintah per semua nama file, tidak satu kali per nama file.

Nb: dengan ';'itu akan menjadi sekali per nama file.

Selain itu, jika Anda menggunakannya untuk memproses kode sumber, Anda dapat melihat ack, yang dibuat untuk mencari bit kode dengan mudah.

ack

Edit:

Anda dapat memperluas penelitian itu sedikit. Pertama, Anda dapat menggunakan -name ''sakelar finduntuk mencari file dengan pola penamaan yang spesifik.

Contohnya :

  • hanya file yang terkait dengan log: -name '*.log'

  • hanya file yang sesuai dengan header c, tetapi Anda tidak bisa menggunakan huruf besar atau kecil untuk ekstensi nama file Anda: -iname *.c

Nb: suka untuk grepdan ack, -isakelar berarti case-sensitive dalam hal ini.

Dalam hal ini, grep akan ditampilkan tanpa warna dan tanpa nomor garis.

Anda dapat mengubah itu dengan --colordan -nswitch (masing-masing warna dan nomor baris dalam file).

Pada akhirnya, Anda dapat memiliki sesuatu seperti:

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

contohnya

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
./test2/target.c:1:hello

5
ackbesar, dan lebih cepat versi ackyaitu ag(pencari perak, geoff.greer.fm/ag )
cfeduke

1
Saya lebih suka ini dengan filter seperti -name '*.log'Ini lebih cepat.
sdkks

@cfeduke Saya belum mencobanya, sebagian besar karena ag bukan bagian dari repositori apt apt di WSL (Anda harus bekerja dengan apa yang Anda dapatkan!)
Pierre-Antoine Guillaume

Triknya adalah menambahkan / dev / null ke grep agar nama file muncul.
ChuckCottrill

Triknya adalah dengan mencari hanya direktori dan kemudian -exec grep / dev / null {} / * untuk mendapatkan semua file dengan satu garpu / exec per direktori.
ChuckCottrill

12

Jika Anda ingin rekursi menjadi subdirektori:

grep -R 'pattern' .

The -Rpilihan adalah bukan pilihan yang standar, tetapi didukung oleh paling umum grepimplementasi.


7
Gunakan -ralih-alih -Runtuk melewatkan symlink ketika GNU grep terkait
αғsнιη

1
@ AFSHIN Mengapa Anda tidak ingin mengikuti symlink?
Kusalananda

4
@Kusalananda Recursion? Meskipun grepimplementasi GNU saat ini menangkap rekursi, saya pikir. Kalau tidak, itu tergantung pada apa yang Anda maksud dengan "tree".
Philippos

2
@Philippos IMHO, mengasuh pengguna bukanlah sesuatu yang grepharus dilakukan oleh alat . Jika pengguna memiliki loop tautan simbolis dalam struktur direktori mereka, well, itu masalah pengguna :-)
Kusalananda

3
@ Kusalananda Dan jika sistem menyediakan loop? Tidak pernah tersesat di /sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...(-XI seperti alat menjaga saya (kecuali mereka memberikan sihir aneh yang mereka sebut "AI"). (-;
Philippos

5

Seperti disebutkan di atas -ratau -R(tergantung pada penanganan symlink yang diinginkan) adalah opsi cepat.

Namun -d <action>bisa bermanfaat sesekali.

Yang menyenangkan -dadalah perintah lewati, yang membungkam "grep: directory_name: Is a direktori" ketika Anda hanya ingin memindai level saat ini.

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  
$ 

dan tentu saja:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  
$ 

The -d skippilihan adalah benar-benar berguna dalam script lain sehingga Anda tidak perlu 2> /dev/null. :)


0

Jika Anda berurusan dengan banyak file, grep berjalan lebih cepat jika Anda memangkas file yang perlu dicari alih-alih mengambil semua file dalam subfolder.

Saya terkadang menggunakan format ini:

grep "primary" `find . | grep cpp$`

Temukan semua file dalam subfolder .yang berakhir di cpp. Kemudian ambil file-file itu untuk "primer".

Jika mau, Anda dapat terus memipatkan hasil tersebut ke panggilan grep lebih lanjut:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"

1
backtics bukan praktik modern yang baik, semuanya sudah usang
Christopher

1
Ini akan rusak jika Anda memiliki file dengan karakter khusus di namanya. Saya tidak tahu betapa istimewanya mereka untuk menjadi terlalu istimewa untuk bekerja sebagaimana mestinya, tetapi apa yang Anda lakukan benar-benar sama dengan mem-parsing output ls, yang juga buruk.
CVn
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.