Cara menggunakan perintah "grep" untuk menemukan teks termasuk subdirektori

373

Saya ingin menemukan semua file yang berisi string teks tertentu. The grepperintah bekerja, tapi saya tidak tahu bagaimana menggunakannya untuk setiap direktori (saya hanya bisa melakukannya untuk direktori saya saat ini). Saya mencoba membaca man grep, tetapi tidak membuahkan hasil.

Senyum. Pemburu
sumber
grep -RIn <nama pola> * Akan mencari dari direktori saat ini di semua file teks. Tidak yakin bagaimana melakukan pencarian saya secara rekursif dalam pola file seperti * .C dengan hanya grep
1
Wildcard dengan --include="*.C"opsi, @ user311346, terima kasih kepada @Lekensteyn.
Bob Stein
Gunakan kombinasi find dan grep untuk mencari file secara string untuk string di direktori saat ini dan semua. Lihat wilddiary.com/find-files-containing-my-text
Drona

Jawaban:

487

Akan lebih baik digunakan

grep -rl "string" /path

dimana

  • -r(atau --recursive) opsi digunakan untuk melintasi juga semua sub-direktori /path, sedangkan
  • -l--files-with-matchesOpsi (atau ) digunakan untuk hanya mencetak nama file file yang cocok, dan bukan baris yang cocok (ini juga dapat meningkatkan kecepatan, mengingat bahwa grepberhenti membaca file pada awalnya cocok dengan opsi ini).
enzotib
sumber
13
Sebenarnya jika "string" adalah pola teks untuk ditemukan, lebih baik menggunakan fungsi itu, jika tidak seseorang dapat menghadapi masalah ketika string berisi titik atau karakter khusus yang memiliki makna dalam ekspresi reguler dan bukan hanya titik yang harus ditemukan sebagai string , dengan adanya. Kemudian saya akan menggunakan -rlFswitch, -Funtuk "string tetap" (dan bukan regexp - misalnya). Tentu saja, jika tugas itu menggunakan regexps, maka permisi. Tentu saja, teori yang sama tanpa -r juga, saya sering melihat bahwa orang menganggap pencarian grep "teks" dan itu dapat menyebabkan masalah mana yang khusus yang berarti sesuatu sebagai regexp.
LGB
4
Ada juga -iflag yang mengabaikan case.
Marco Ceppi
3
Saya hanya akan menunjukkan --recursiveopsi, ada banyak opsi dan skenario penggunaan yang bisa dibicarakan. Saya mulai dari jawaban yang diterima @dmityugov dan dimodifikasi untuk bekerja tanpa find.
enzotib
1
@NN: selesai :-)
enzotib
3
@ScottBiggs: dengan opsi--include '*.h'
enzotib
167

Jika Anda mencari baris yang cocok dengan file, perintah favorit saya adalah:

grep -Hrn 'search term' path/to/files
  • -H menyebabkan nama file dicetak (tersirat ketika banyak file dicari)
  • -r melakukan pencarian rekursif
  • -n menyebabkan nomor baris dicetak

path/to/filesbisa .dengan mencari di direktori saat ini

Opsi lebih lanjut yang menurut saya sangat berguna:

  • -Iabaikan file biner (komplemen: -amemperlakukan semua file sebagai teks)
  • -Fperlakukan search termsebagai literal, bukan ekspresi reguler
  • -i lakukan pencarian case-insensitive
  • --color=alwaysuntuk memaksa warna bahkan ketika disalurkan melalui less. Untuk membuat lesswarna dukungan, Anda perlu menggunakan -ropsi:

    grep -Hrn search . | less -r
    
  • --exclude-dir=dirberguna untuk mengecualikan direktori seperti .svndan .git.

Contoh output

Lekensteyn
sumber
13
-Hpada folder berlebihan, jika ada lebih dari satu file, seperti kemungkinan. Faktanya, halaman manual mengatakan-H, --with-filename: Print the file name for each match. This is the default when there is more than one file to search.
enzotib
Saya tidak tahu itu, selalu berhasil seperti yang saya harapkan. Ini perintah default saya ketika mencari file.
Lekensteyn
1
Apakah ada cara untuk hanya mempertimbangkan file dengan, katakanlah, ekstensi. (Dan untuk menggabungkan ini dengan -r)?
user2413
6
@ user2413 Coba--include '*.*'
Lekensteyn
1
@alper Trygrep --exclude='*~' ...
Lekensteyn
24

Saya yakin Anda bisa menggunakan sesuatu seperti ini:

find /path -type f -exec grep -l "string" {} \;

Penjelasan dari komentar

findadalah perintah yang memungkinkan Anda menemukan file dan objek lain seperti direktori dan tautan dalam subdirektori dari jalur yang diberikan. Jika Anda tidak menentukan topeng yang harus dipenuhi oleh nama file, itu menyebutkan semua objek direktori.

  • -type f menetapkan bahwa ia hanya boleh memproses file, bukan direktori, dll.
  • -exec grepmenetapkan bahwa untuk setiap file yang ditemukan, ia harus menjalankan perintah grep, meneruskan nama filenya sebagai argumen, dengan mengganti {}dengan nama file
dmityugov
sumber
3
Hanya untuk mereka yang tidak tahu, menambahkan -name '*.py'membatasi pertandingan ke file yang berakhiran '.py'.
Daniel F
Saya suka bahwa ini mencakup klien yang tidak memiliki -R diimplementasikan dalam perintah grep mereka.
Aviose
Jika Anda ingin garis yang cocok DAN nama file dicetak, buat exec seperti:... -exec bash -c 'grep -r "mystring" {} && echo {}' \;
Donn Lee
apa kinerja relatif hanya menggunakan grep secara langsung?
Jonathan
19

Perintah default saya adalah

grep -Rin string *

Saya menggunakan capitol 'R' karena lsmenggunakannya untuk rekursif. Karena grep menerima keduanya, tidak ada alasan untuk tidak menggunakannya.

EDIT: per HVNSweeting, tampaknya -Rakan mengikuti symlink dimana -rtidak akan.

pengguna606723
sumber
1
Untuk mencari di file tersembunyi juga, jalankan shopt -s dotglob(ingat -ssebagai "set"). Hati-hati saat menghapus file. Jika Anda sudah mengaktifkan dotglob, rm -r *hapus semua yang ada di dir saat ini, tetapi juga direktori di atasnya karena ..cocok. Untuk menonaktifkan dotglob, gunakan shopt -u dotglob("unset"). Perubahannya bersifat sementara, itu hanya berlaku untuk shell saat ini.
Lekensteyn
Saya lupa tentang ini. Apakah ada cara untuk mengaturnya untuk satu baris? sesuatu seperti shopt -s dotglob & <grep cmd> & shopt -y dotglobhanya lebih nyaman? Dengan cara ini kita tidak perlu khawatir tentang mengatur ulang
user606723
Juga, mungkin lebih mudah digunakan grep -Rin string .dalam sebagian besar kasus ini. Saya hanya menggunakan * karena tampaknya lebih alami.
user606723
1
jika Anda melakukan grep rekursif, maka Anda bisa mulai dari "." dari pada "*". tidak perlu dotglob.
Michał Šrajer
1
pilih ini, satu hal yang tidak disebutkan di halaman manual adalah Rakan mengikuti tautan simbolis, rtidak
HVNSweeting
12

Jika Anda ingin mencoba sesuatu yang baru, coba ack. Perintah untuk mencari direktori saat ini secara rekursif stringadalah:

ack string

Instalasi cukup sederhana:

curl http://betterthangrep.com/ack-standalone > ~/bin/ack && chmod 0755 !#:3

(Asalkan Anda sudah memiliki direktori ~/bindan lebih disukai di PATH.)

Konrad Rudolph
sumber
2
Atau cukup gunakan apt-get install ack-grep (, dan tambahkan alias ack = ack-grep ke .bashrc Anda)
markijbema
Apa yang dilakukan parameter terakhir pada chmodperintah? Apakah mereka khusus chmodatau terkait bash ( !#:3bagian)?
Elliott Darfink
@ElliottDarfink Itu menggunakan Bash fitur sejarah - !adalah penanda acara . Mereka cukup kuat untuk menghindari pengulangan. !#:3referensi token ketiga dari baris perintah sejauh ini, yaitu ~/bin/ackdalam hal ini.
Konrad Rudolph
4

Perintah rgrep didedikasikan untuk kebutuhan seperti itu

Jika tidak tersedia, Anda bisa mendapatkannya seperti ini

mkdir -p ~/bin
cd ~/bin
wget http://sdjf.esmartdesign.com/files/rgrep
chmod +x rgrep

Anda dapat langsung menetapkan opsi grep default seperti dijelaskan di atas.

Saya personnaly gunakan

[[  ${#args} -lt 5 && "${args//[[:space:]]/}" == "-i" ]] && args="-Hin"
args="${args:--Hns} --color=auto"

topik terkait: bagaimana cara selalu menggunakan rgrep dengan warna

mnono
sumber
rgrep disediakan oleh paket grep yang diinstal secara default di Ubuntu.
karel
2

Pembaruan 2:

Baris perintah ini menggunakan finddan grepmemperbaiki masalah:

$ find path_to_search_in -type f -exec grep -in searchString {} 2> /dev/null +

--color=<always or auto> untuk output berwarna:

$ find path_to_search_in -type f \
            -exec grep --color=always -in searchString {} 2>/dev/null +

Contoh:

$ find /tmp/test/ -type f -exec grep --color=auto -in "Search string" {} 2>/dev/null +

Contoh dijalankan dalam snapshot di bawah ini: snap1


Pembaruan 1:

Anda dapat mencoba kode berikut; sebagai fungsi di skrip Anda .bashrcatau .bash_aliasesatau di:

wherein () 
{ 
    for i in $(find "$1" -type f 2> /dev/null);
    do
        if grep --color=auto -i "$2" "$i" 2> /dev/null; then
            echo -e "\033[0;32mFound in: $i \033[0m\n";
        fi;
    done
}

Pemakaian: wherein /path/to/search/in/ searchkeyword

contoh:

$ wherein ~/Documents/ "hello world"

(Catatan: Seperti yang disarankan dalam komentar di bawah ini oleh @enzotib, ini tidak berfungsi dengan file / direktori termasuk spasi di namanya).


Pos asli

Untuk mencari string dan output sesuai dengan string pencarian:

$ for i in $(find /path/of/target/directory -type f); do \
    grep -i "the string to look for" "$i"; done

misalnya:

$ for i in $(find /usr/share/applications -type f); \
    do grep -i "web browser" "$i"; done

Untuk menampilkan nama file yang berisi string pencarian:

$ for i in $(find /path/of/target/directory -type f); do \
    if grep -i "the string to look for" "$i" > /dev/null; then echo "$i"; fi; done;

misalnya:

$ for i in $(find /usr/share/applications -type f); \
    do if grep -i "web browser" "$i" > /dev/null; then echo "$i"; \
    fi; done;
tepat
sumber
Gagal pada nama file yang mengandung spasi. Gagal disembunyikan oleh fakta bahwa stderr tidak ditampilkan.
enzotib
@enzotib terima kasih untuk menunjukkan itu .. itu masih belum terselesaikan untuk fungsi yang ditentukan .. Saya sudah menambahkan satu-liner sekalipun ..
tepat
Sekarang jawabannya mirip dengan @dmityugov.
enzotib
ya, tetapi dalam pengertian itu sebagian besar jawaban di halaman ini jika Anda memeriksa serupa dalam hal yang mereka gunakan grep, di samping itu menjadi subset menggunakan finddengan grep... tetapi jika Anda menerima switch dan tweak yang berbeda sebagai jawaban yang berbeda, mungkin milik saya akan cocok di sini juga .. atau apakah Anda berbeda? pembaruan terakhir melakukan apa yang saya inginkan dalam pencarian saya: nama file dengan baris dengan kunci pencarian dan baris no. juga :) dan keluaran berwarna dan filter kesalahan untuk keterbacaan yang lebih baik ..
tepat
2

grep( GNU atau BSD )

Anda dapat menggunakan grepalat untuk mencari secara rekursif folder saat ini dengan -rparameter, seperti:

grep -r "pattern" .

Catatan: -r- Sub direktori pencarian secara rekursif.

Untuk mencari di dalam file tertentu, Anda dapat menggunakan sintaks globbing seperti:

grep "class foo" **/*.c

Catatan: Dengan menggunakan opsi globbing ( **), ia memindai semua file secara rekursif dengan ekstensi atau pola tertentu. Untuk mengaktifkan sintaks ini, jalankan: shopt -s globstar. Anda juga dapat menggunakan **/*.*untuk semua file (tidak termasuk tersembunyi dan tanpa ekstensi) atau pola lainnya.

Jika Anda memiliki kesalahan karena argumen Anda terlalu panjang, pertimbangkan untuk mempersempit pencarian Anda, atau gunakan findsintaksis seperti:

find . -name "*.php" -execdir grep -nH --color=auto foo {} ';'

Atau gunakan ripgrep.

ripgrep

Jika Anda bekerja pada proyek-proyek yang lebih besar atau file-file besar, Anda harus menggunakan ripgrepsebaliknya, seperti:

rg "pattern" .

Periksa dokumen, langkah-langkah instalasi atau kode sumber pada halaman proyek GitHub .

Ini jauh lebih cepat daripada alat lain seperti GNU / BSD grep , ucg, ag, sift, ack, ptatau serupa, karena dibangun di atas mesin regex Rust ini yang menggunakan automata terbatas, SIMD dan optimasi literal agresif untuk membuat pencarian sangat cepat.

Ini mendukung pola abaikan yang ditentukan dalam .gitignorefile, sehingga jalur file tunggal dapat dicocokkan dengan beberapa pola glob secara bersamaan.


Anda dapat menggunakan parameter umum seperti:

  • -i - Pencarian tidak sensitif.
  • -I - Abaikan file biner.
  • -w - Cari seluruh kata (berlawanan dengan pencocokan sebagian kata).
  • -n - Tampilkan garis pertandingan Anda.
  • -C/ --context(eg -C5) - Meningkatkan konteks, sehingga Anda melihat kode di sekitarnya.
  • --color=auto - Tandai teks yang cocok.
  • -H - Menampilkan nama file tempat teks ditemukan.
  • -c- Menampilkan hitungan garis yang cocok. Dapat dikombinasikan dengan -H.
kenorb
sumber
1

Saya melakukan ini menggunakan xargs, perintah yang sangat diremehkan

find ./ -type f -print0 | xargs -0 grep 'string_you_are_looking_for'

find ./ memberi Anda daftar rekursif dari semua file di folder saat ini kemudian Anda pipa ke xargs yang mengeksekusi perintah grep pada masing-masing file tersebut

deadprogrammer
sumber
4
Menggunakan xargstanpa -print0opsi ke finddan -0opsi untuk xargstidak digunakan lagi, itu akan gagal pada nama file yang mengandung spasi.
enzotib
@enzotib Saya telah mengedit jawaban seperti yang Anda sarankan.- silakan tinjau dan jika perlu mengedit dan memperbaiki, saya akan senang mengedit ulang oleh Anda. terima kasih
αғsнιη
1
@KasiyA: tidak apa-apa sekarang, menghapus downvote saya.
enzotib
0

Saya tahu ada banyak jawaban di sini, tetapi inilah alternatif jika Anda ingin menambahkan batasan lain saat mencari file:

find . -type f -exec grep --quiet string_to_look_for {} ';' -print

Ini berfungsi karena grepakan mengembalikan 0 jika menemukan hasil, 1 sebaliknya. Misalnya Anda dapat menemukan file berukuran 1 MB dan berisi sesuatu:

find . -type f -exec grep --quiet string_to_look_for {} ';' -size 1M -print

Untuk beberapa persyaratan, Anda mungkin ingin menggunakan bendera pengoptimal -Oyang ada di GNU grep.

Ztyx
sumber
0

Sebuah skrip (find-in-code) untuk dicari dalam C, kode CPP:

#!/bin/sh

find . \( -iname "*.c" -o -iname "*.cpp" -o -iname "*.h" \) -type f -print0 | xargs -0 grep --color -n "$1"

Menggunakan:

find-in-code "search string"
nvd
sumber