Gunakan grep --exclude / - include sintaks untuk tidak grep melalui file-file tertentu

780

Saya mencari string foo=dalam file teks di pohon direktori. Ada di mesin Linux yang umum, saya punya bash shell:

grep -ircl "foo=" *

Dalam direktori juga banyak file biner yang cocok dengan "foo =". Karena hasil ini tidak relevan dan memperlambat pencarian, saya ingin grep melewati pencarian file-file ini (kebanyakan gambar JPEG dan PNG). Bagaimana saya melakukannya?

Saya tahu ada opsi --exclude=PATTERNdan --include=PATTERN, tapi apa format pola? Halaman manual grep mengatakan:

--include=PATTERN     Recurse in directories only searching file matching PATTERN.
--exclude=PATTERN     Recurse in directories skip file matching PATTERN.

Pencarian di grep meliputi , grep termasuk mengecualikan , grep mengecualikan dan varian tidak menemukan sesuatu yang relevan

Jika ada cara yang lebih baik untuk menangkap hanya dalam file-file tertentu, saya siap untuk itu; memindahkan file yang menyinggung bukanlah pilihan. Saya tidak dapat mencari hanya direktori tertentu (struktur direktori berantakan, dengan semuanya ada di mana-mana). Juga, saya tidak dapat menginstal apa-apa, jadi saya harus melakukan dengan alat umum (seperti grep atau disarankan find ).

Piskvor meninggalkan gedung
sumber
13
Hanya FYI, argumen yang digunakan: -c menghitung kecocokan dalam file -i-case-tidak sensitif -l hanya menunjukkan file yang cocok -r rekursif
Piskvor meninggalkan gedung
68
Cara yang lebih cepat untuk mengecualikan dir svn adalah --exclude-dir=.svn, jadi grep tidak masuk ke mereka sama sekali
orip
25
Beberapa poin pedantic yang mungkin perlu diketahui orang: 1. Catat kurangnya kutipan di sekitar glob di sini: --exclude = ' . {Png, jpg}' tidak berfungsi (setidaknya dengan versi grep GNU saya) karena grep tidak mendukung {} di gumpalannya. Di atas adalah shell-diperluas ke '--exclude = .png --exclude = *. Jpg' (dengan asumsi tidak ada file yang cocok dengan cwd - sangat tidak mungkin karena Anda biasanya tidak memulai nama file dengan '--exclude =') yang grep suka saja. 2. --exclude adalah ekstensi GNU dan bukan bagian dari definisi POSIX tentang grep, jadi jika Anda menulis skrip menggunakan ini, ketahuilah mereka tidak akan berjalan pada sistem non-GNU.
ijw
2
Contoh lengkap penggunaan exclude-dir:grep -r --exclude-dir=var "pattern" .
Tisch

Jawaban:

767

Gunakan sintaks globbing shell:

grep pattern -r --include=\*.{cpp,h} rootdir

Sintaks untuk --excludeidentik.

Perhatikan bahwa bintang tersebut lolos dengan garis miring terbalik untuk mencegahnya diperluas oleh shell (mengutipnya, seperti --include="*.{cpp,h}", akan bekerja dengan baik juga). Kalau tidak, jika Anda memiliki file di direktori kerja saat ini yang cocok dengan pola, baris perintah akan meluas ke sesuatu seperti grep pattern -r --include=foo.cpp --include=bar.h rootdir, yang hanya akan mencari file bernama foo.cppdan bar.h, yang kemungkinan besar tidak seperti yang Anda inginkan.

Adam Rosenfield
sumber
8
Saya tidak tahu mengapa, tapi saya harus mengutip pola sertakan seperti ini:grep pattern -r --include="*.{cpp,h}" rootdir
topek
6
@topek: Poin bagus - jika Anda memiliki file .cpp / .h di direktori Anda saat ini, maka shell akan memperluas glob sebelum memanggil grep, jadi Anda akan berakhir dengan baris perintah seperti grep pattern -r --include=foo.cpp --include=bar.h rootdir, yang hanya akan mencari file bernama foo.cppatau bar.h. Jika Anda tidak memiliki file yang cocok dengan glob di direktori saat ini, maka shell meneruskan glob untuk grep, yang menafsirkannya dengan benar.
Adam Rosenfield
6
Saya baru menyadari bahwa glob digunakan hanya untuk mencocokkan nama file. Untuk mengecualikan seluruh direktori satu --exclude-diropsi perlu . Aturan yang sama berlaku. Hanya nama file direktori yang cocok, bukan jalan.
Krzysztof Jabłoński
3
--includesepertinya tidak berhasil setelahnya --exclude. Saya kira tidak masuk akal untuk mencoba, kecuali bahwa saya harus memahami aliasdaftar panjang --excludedan --exclude-dir, yang saya gunakan untuk mencari kode, mengabaikan perpustakaan dan bertukar file dan hal-hal. Aku akan berharap bahwa grep -r --exclude='*.foo' --include='*.bar'akan bekerja, sehingga saya bisa membatasi saya aliasuntuk --include='*.bar'hanya, tetapi tampaknya mengabaikan --includedan termasuk segala sesuatu yang bukan file .foo. Menukar urutan --includedan --excludebekerja, tetapi sayangnya, itu tidak membantu saya alias.
Michael Scheper
1
bagaimana kita bisa membaca pikiran seseorang untuk mendapatkan aturan untuk ini PATTERN. Setengah jam saya tidak dapat menemukan penjelasan apa pun yang mereka tunggu di sana
Arkady
221

Jika Anda hanya ingin melewatkan file biner, saya sarankan Anda melihat opsi -I(huruf besar i). Itu mengabaikan file biner. Saya secara teratur menggunakan perintah berikut:

grep -rI --exclude-dir="\.svn" "pattern" *

Itu mencari secara rekursif, mengabaikan file biner, dan tidak melihat ke dalam folder tersembunyi Subversion, untuk pola apa pun yang saya inginkan. Saya memilikinya alias "grepsvn" di kotak saya di tempat kerja.

rmeador
sumber
1
Terima kasih, itu sangat berguna untuk beberapa skenario lain yang saya temui.
Piskvor meninggalkan gedung
25
--exclude-dirtidak tersedia di mana-mana. kotak RH saya bekerja dengan GNU grep 2.5.1 tidak memilikinya.
gcb
Ada saran untuk apa yang harus digunakan ketika --exclude-dirtidak tersedia? Dalam semua upaya saya, --excludetampaknya tidak sesuai dengan tagihan.
JMTyler
Anda selalu dapat mengunduh sumber grep terbaru dari GNU, dan melakukan 'configure; membuat; sudo make install '. Ini adalah salah satu hal pertama yang saya lakukan pada Mac atau distribusi Linunx yang lebih lama.
Jonathan Hartley
3
Apa yang saya butuhkan. Sebenarnya, saya menggunakan git. Jadi, --exclude-dir="\.git". :-)
Ionică Bizău
66

Silakan lihat ack , yang dirancang untuk situasi ini. Contoh Anda dari

grep -ircl --exclude=*.{png,jpg} "foo=" *

dilakukan dengan ack as

ack -icl "foo="

karena ack tidak pernah melihat file biner secara default, dan -r diaktifkan secara default. Dan jika Anda hanya menginginkan file CPP dan H, lakukan saja

ack -icl --cpp "foo="
Andy Lester
sumber
Terlihat bagus, akan mencoba versi mandiri lain kali, terima kasih.
Piskvor meninggalkan gedung
5
Panggilan bagus, saya tidak bisa lagi hidup tanpa ACK.
Peluang
1
stackoverflow.com/questions/667471/… - Ini akan memungkinkan Anda untuk mendapatkan ack di windows, jika di situlah Anda menjalankan grep.
TamusJRoyce
@ Peluang Mungkin Anda ingin silversearcher-ag , hanya apt-getdi Ubuntu :)
Justme0
jangan dikacaukan denganawk
jasonleonhard
35

grep 2.5.3 memperkenalkan parameter --exclude-dir yang akan bekerja seperti yang Anda inginkan.

grep -rI --exclude-dir=\.svn PATTERN .

Anda juga dapat mengatur variabel lingkungan: GREP_OPTIONS = "- exclude-dir = .svn"

Saya akan memilih Andy kedua untuk ack , itu yang terbaik.

Corey
sumber
7
+1 untuk menyebutkan nomor versi persisnya; Saya punya grep 2.5.1 dan opsi mengecualikan-dir tidak tersedia
James
25

Saya menemukan ini setelah waktu yang lama, Anda dapat menambahkan beberapa menyertakan dan mengecualikan seperti:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js
Rushabh Mehta
sumber
5
Lebih baik untuk menggabungkan mereka dalam daftar seperti: --exclude = {pattern1, pattern2, pattern3}
Yasser Sinjab
12

Perintah yang disarankan:

grep -Ir --exclude="*\.svn*" "pattern" *

secara konseptual salah, karena --exclude bekerja pada nama dasar. Dengan kata lain, ini hanya akan melewatkan .svn di direktori saat ini.


sumber
3
Ya, itu tidak bekerja sama sekali untuk saya. Salah satu yang bekerja untuk saya adalah: exclude-dir = .svn
Taryn East
2
@Nicola terima kasih! Saya sudah merobek rambut saya tentang mengapa ini tidak berhasil. Katakan padaku, adakah cara untuk menemukan ini dari halaman manual? Semua yang dikatakannya cocok dengan "POLA". Halaman manual EDIT mengatakan "file", seperti yang dijelaskan di sini fixunix.com/unix/…
13ren
11

Di grep 2.5.1 Anda harus menambahkan baris ini ke profil ~ / .bashrc atau ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"
deric
sumber
9

Saya menemukan kadang-kadang grepping keluaran grep sangat membantu:

grep -rn "foo=" . | grep -v "Binary file"

Padahal, itu tidak benar-benar menghentikannya dari mencari file biner.

Aaron Maenpaa
sumber
10
Anda dapat menggunakan grep -Iuntuk melewati file biner.
Nathan Fellman
juga telah melakukan itu ketika saya masih muda ... sekarang saya tahu lebih baik dan ketika dihadapkan dengan masalah, hal pertama adalah RTFM
gcb
grepping grep akan menghapus highlight warna.
Max Li
7

Jika Anda tidak suka menggunakan find, saya suka -prunefiturnya:

find [directory] \
        -name "pattern_to_exclude" -prune \
     -o -name "another_pattern_to_exclude" -prune \
     -o -name "pattern_to_INCLUDE" -print0 \
| xargs -0 -I FILENAME grep -IR "pattern" FILENAME

Pada baris pertama, Anda menentukan direktori yang ingin Anda cari. .(direktori saat ini) adalah jalur yang valid, misalnya.

Pada tanggal 2 dan garis-3, penggunaan "*.png", "*.gif", "*.jpg", dan sebagainya. Gunakan sebanyak ini-o -name "..." -prune konstruksi sebanyak yang Anda punya pola.

Pada baris ke-4, Anda memerlukan yang lain -o(ini menentukan "atau" untuk find), pola yang Anda inginkan, dan Anda perlu a -printatau -print0di akhir. Jika Anda hanya ingin "segala sesuatu yang lain" yang tetap setelah pemangkasan *.gif, *.pngdll gambar, maka penggunaan -o -print0 dan Anda selesai dengan garis-4.

Akhirnya, pada baris ke-5 adalah pipa xargsyang mengambil masing-masing file yang dihasilkan dan menyimpannya dalam suatu variabel FILENAME. Kemudian melewati grepsatu -IRbendera, yang "pattern", dan kemudian FILENAMEdiperluas oleh xargsuntuk menjadi yang daftar nama file ditemukan olehfind .

Untuk pertanyaan khusus Anda, pernyataan itu mungkin terlihat seperti:

find . \
     -name "*.png" -prune \
     -o -name "*.gif" -prune \
     -o -name "*.svn" -prune \
     -o -print0 | xargs -0 -I FILES grep -IR "foo=" FILES

OnlineCop
sumber
Satu amandemen yang saya sarankan: sertakan -falsesegera setelah masing-masing -prunejadi lupa untuk menggunakan -print0atau semacam execperintah tidak akan benar-benar mencetak file yang ingin Anda kecualikan: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop
7

Pada CentOS 6.6 / Grep 2.6.3, saya harus menggunakannya seperti ini:

grep "term" -Hnir --include \*.php --exclude-dir "*excluded_dir*"

Perhatikan kurangnya tanda-tanda sama "=" (jika tidak --include, --exclude, include-dirdan --exclude-dirdiabaikan)

aesede
sumber
6

git grep

Gunakan git grepyang dioptimalkan untuk kinerja dan bertujuan untuk mencari melalui file-file tertentu.

Secara default ia mengabaikan file biner dan itu menghormati Anda .gitignore. Jika Anda tidak bekerja dengan struktur Git, Anda masih bisa menggunakannya dengan melewati--no-index .

Sintaks contoh:

git grep --no-index "some_pattern"

Untuk lebih banyak contoh, lihat:

kenorb
sumber
5

Saya seorang dilettante, memang begitu, tapi begini tampilannya ~ / .bash_profile saya:

export GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

Perhatikan bahwa untuk mengecualikan dua direktori, saya harus menggunakan --exclude-dir dua kali.

4D4M
sumber
3

Jika Anda mencari secara non-rekursif, Anda dapat menggunakan pola glop untuk mencocokkan nama file.

grep "foo" *.{html,txt}

termasuk html dan txt. Hanya mencari di direktori saat ini.

Untuk mencari di subdirektori:

   grep "foo" */*.{html,txt}

Dalam subdirektori:

   grep "foo" */*/*.{html,txt}
Stéphane Laurent
sumber
3

Dalam direktori juga banyak file biner. Saya tidak bisa mencari hanya direktori tertentu (struktur direktori berantakan). Apakah ada cara yang lebih baik untuk menangkap hanya dalam file tertentu?

ripgrep

Ini adalah salah satu alat tercepat yang dirancang untuk mencari direktori Anda saat ini secara rekursif. Itu ditulis dalam Rust , dibangun di atas mesin regex Rust untuk efisiensi maksimum. Periksa analisis terperinci di sini .

Jadi Anda bisa menjalankan:

rg "some_pattern"

Ini menghormati Anda .gitignoredan secara otomatis melewati file / direktori tersembunyi dan file biner.

Anda masih dapat menyesuaikan menyertakan atau mengecualikan file dan direktori menggunakan -g/ --glob. Aturan gumpal cocok dengan .gitignoregumpalan. Periksa man rgbantuan.

Untuk contoh lainnya, lihat: Bagaimana cara mengecualikan beberapa file yang tidak cocok dengan ekstensi tertentu dengan grep?

Di macOS, Anda dapat menginstal via brew install ripgrep.

kenorb
sumber
3

find dan xargs adalah temanmu. Gunakan mereka untuk memfilter daftar file daripada grep --exclude

Coba sesuatu seperti

find . -not -name '*.png' -o -type f -print | xargs grep -icl "foo="

Keuntungan dari membiasakan diri dengan ini, adalah dapat diperluas ke kasus penggunaan lain, misalnya untuk menghitung baris di semua file non-png:

find . -not -name '*.png' -o -type f -print | xargs wc -l

Untuk menghapus semua file non-png:

find . -not -name '*.png' -o -type f -print | xargs rm

dll.

Seperti yang ditunjukkan dalam komentar, jika beberapa file memiliki spasi dalam namanya, gunakan -print0dan xargs -0sebagai gantinya.

Andrew Stein
sumber
1
Ini tidak berfungsi pada nama file dengan spasi, tetapi masalah itu mudah diselesaikan dengan menggunakan print0 alih-alih mencetak dan menambahkan opsi -0 ke xargs.
Adam Rosenfield
2

skrip tersebut tidak menyelesaikan semua masalah ... Coba ini lebih baik:

du -ha | grep -i -o "\./.*" | grep -v "\.svn\|another_file\|another_folder" | xargs grep -i -n "$1"

skrip ini sangat baik, karena menggunakan ekspresi reguler "nyata" untuk menghindari direktori dari pencarian. cukup pisahkan nama folder atau file dengan "\ |" pada grep -v

bersenang senang lah! ditemukan di shell linux saya! XD


sumber
2

Lihat @ yang ini.

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags
suhas tawade
sumber
2
Hal-hal yang mencapai kira-kira ini telah dibahas dalam posting lain; Terlebih lagi, ini salah, karena dengan berbagai opsi tata letak yang ditetapkan itu akan mengacaukan nomor baris dan hal-hal seperti itu atau mengecualikan garis konteks yang diinginkan.
Chris Morgan
bagaimana Anda bisa menggunakan beberapa opsi "-v" secara bersamaan?
Buka jalan
1

The --binary-files=without-matchpilihan untuk GNUgrep mendapatkannya untuk melewati file biner. (Setara dengan-I sakelar yang disebutkan di tempat lain.)

(Ini mungkin memerlukan versi terbaru grep; 2.5.3 memilikinya, setidaknya.)

mjs
sumber
1

cocok untuk file .alias tcsh:

alias gisrc 'grep -I -r -i --exclude="*\.svn*" --include="*\."{mm,m,h,cc,c} \!* *'

Butuh waktu beberapa saat untuk mengetahui bahwa bagian {mm, m, h, cc, c} TIDAK boleh berada di dalam tanda kutip. ~ Keith

Keith Knauber
sumber
0

Untuk mengabaikan semua hasil biner dari grep

grep -Ri "pattern" * | awk '{if($1 != "Binary") print $0}'

Bagian awk akan menyaring semua file yang cocok dengan file Biner

lathomas64
sumber
-2

Coba ini:

  1. Buat folder bernama " --F" di bawah currdir .. (atau tautkan folder lain di sana diganti namanya menjadi " --F" yaitu double-minus-F.
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
P Stack
sumber