grep แบบเรียกซ้ำ: ยกเว้นไดเรกทอรีที่เฉพาะเจาะจง


49

ฉันใช้ grep แบบเรียกซ้ำจำนวนมากเพื่อค้นหาไฟล์ต้นฉบับที่มีเนื้อหาเฉพาะ

grep -Rni "myfunc" .

บนฐานโค้ดขนาดใหญ่สิ่งนี้อาจช้าได้ดังนั้นฉันใช้ --incldue เพื่อ จำกัด / ส่วนขยายรายการที่อนุญาต

grep -Rni --include=*.java "myfunc" .

อย่างไรก็ตามมันจะมีประสิทธิภาพมากกว่าที่จะยกเว้นไดเรกทอรีย่อยทั้งหมด (พรุน) ฉันคิดว่า:

grep -Rni --exclude=/.svn/ "myfunc" .

แต่ --exclude รองรับเฉพาะรูปแบบไฟล์เช่น * .java ด้านบน ฉันจะยกเว้นไดเรกทอรีได้อย่างไร

คำตอบ:


10

คุณอาจจะดูเป็นแอ๊กชั่น

ฉันเพิ่งเริ่มใช้มัน แต่มันก็ดูเหมาะสมสำหรับเรื่องนี้


แอ๊ดูดีทีเดียว ดีที่มันสังหรณ์ไม่รวมไฟล์ที่ไม่พึงประสงค์ ตัวเลือก --nogroup ให้ผลลัพธ์คล้ายกับ grep -Rni
gabor

2
Ack ช้าไปหน่อย คุณสามารถลองใช้ The Silver Searcher (Ag) หรือ ripgrep (rg)
user31389

62
grep -r --exclude-dir=dev --exclude-dir=sys --exclude-dir=proc PATTERN data

ที่มา: https://stackoverflow.com/questions/2799246/grep-excluding-a-specific-folder-using


17
โปรดทราบว่าสิ่งนี้จะแยกซ้ำ จะได้รับการยกเว้นพร้อมกับ./dev ./foo/bar/devใช้--exclude-dir=./devเพื่อนำไปใช้กับกรณีแรกเท่านั้น
คอรี่วอล์คเกอร์

4
คุณยังสามารถตัดให้สั้นลงได้โดยการทำให้กลมกลืน: bash grep -r --exclude-dir={dev,sys,proc} PATTERN data ปัญหาเดียวของการทำให้กลมเป็นวงกลมคือฉันไม่สามารถทำให้มันทำงานได้อย่างมีประสิทธิภาพ ในกรณีที่ฉันต้องแยกพวกเขา
b01

3
นอกจากนี้ยังตั้งข้อสังเกตว่า {} ใช้ได้เฉพาะเมื่อคุณใส่มากกว่า 1 รายการนั่นหมายความว่า --exclude-dir = {home, .svn} ใช้งานได้ แต่ --exclude-dir = {. svn} จะไม่ทำงาน มันเสียเวลาที่จะคิดออกว่าทำไม {} ไม่ทำงานเพราะฉันทดสอบกับ 1 รายการในครั้งแรก
皞皞

หากคุณใช้{}กับรายการเดียวคุณอาจต้องใช้เครื่องหมายจุลภาคที่ไม่ต้องแยกเพื่อสร้างอาร์เรย์ (ไม่แน่ใจว่า Bash จัดการกับมันอย่างไร) แทนที่จะทำอย่างนั้นฉันก็สร้างนามแฝงใน. bash_aliases ที่วนซ้ำในรายการโฟลเดอร์ที่ฉันมักจะต้องการแยกออกเช่น. git, .svn, .hg, .cache แล้วเพิ่มมันผ่านลูปด้วย--exclude-dir $dirจากนั้นขยายอาร์เรย์นั้นไปยังนามแฝง grep
dragon788

6

คุณสามารถใช้การค้นหาแทน:

find . -not -path "*/.svn*" -not -type d -exec grep -ni "myfunc" {} \; -print

ตกลงนั่นคือถอยหลังเล็กน้อยคุณจะได้ผลลัพธ์ grep ก่อนแล้วตามด้วยเส้นทาง บางทีคนอื่นมีคำตอบที่ดีกว่า


3
ตกลงฉันชอบมาก แน่นอนว่าการค้นหามีความยืดหยุ่นมากขึ้น ความแตกต่างเพียงอย่างเดียวระหว่างเอาท์พุทคือ "grep -Rni" จะพิมพ์ชื่อไฟล์สำหรับแต่ละคู่ที่ตรงกันในขณะที่ "find -exec grep" จะพิมพ์ชื่อไฟล์ในหนึ่งบรรทัดจากนั้นหนึ่งบรรทัดสำหรับแต่ละคู่ (ด้วยหมายเลขบรรทัดและเนื้อหาของบรรทัด ) การใช้ "grep -Hni" กองกำลังชื่อไฟล์ที่จะแสดงในแต่ละบรรทัด
บอร์

ขอบคุณสำหรับการให้คำตอบเดียวที่ทำงานกับระบบซึ่งเป็นแบบนี้โดยไม่มี grep - exclude-dir แต่ยังต้องทำงานต่อไป
Dmitri DB

2

นี่คือตัวอย่างเต็มรูปแบบจากสคริปต์ในหนึ่งในโครงการของฉันที่อาจช่วยฉันเรียกไฟล์นี้ว่า "all_source" (ทำเครื่องหมายว่าปฏิบัติการได้) และวางไว้ในรูทของโปรเจ็กต์ของฉันจากนั้นเรียกมันว่าgrep myfunc $(./all_source)เรียงลำดับท้ายสคริปต์ทั้งหมด ไม่จำเป็น.

#!/bin/bash

find . \
    -type d \( \
            -wholename './lib' -o \
            -wholename './vc6' -o \
            -name 'gen' -o \
            -name '.svn' \
            \) -prune -o \
    -type f \( \
            -name '*.h' -o \
            -name '*.cpp' -o \
            -name '*.c' -o \
            -name '*.lua' -o \
            -name '*.*awk' \) -print \
    | sort

สคริปต์นี้ส่งคืนชื่อไฟล์ทั้งหมดในโครงการที่ตรงกัน*.h, *.cpp, *.c, *.lua, *.*awkแต่ไม่ค้นหาในทุกโฟลเดอร์ชื่อ. svn และโฟลเดอร์ gen รวมถึงการข้ามโฟลเดอร์./libและ./vc6(แต่เฉพาะที่อยู่ในรูทโครงการ) ดังนั้นเมื่อคุณทำgrep myfunc $(./all_source)มัน greps ในไฟล์เหล่านั้นเท่านั้น คุณจะต้องเรียกสิ่งนี้จาก root dir ของโครงการด้วย


0

นอกจากนี้ยังมีตัวเลือก -prune เพื่อค้นหา:

 find . -path "*/.svn*" -prune -o -not -type d -exec grep -ni "myfunc" {} \; -print

0

คุณสามารถลองทำสิ่งนี้:

grep -R  "myfunc" . | grep -v path_to_exclude/

เช่นถ้าคุณไม่ต้องการค้นหาเนื้อหาในไฟล์บันทึกให้ทำดังนี้:

grep -R "myfunc" . | grep -v log/
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.