ใช้ grep --exclude / - รวมไวยากรณ์เพื่อไม่ grep ผ่านไฟล์บางไฟล์


780

ฉันกำลังมองหาสตริงfoo=ในไฟล์ข้อความในแผนผังไดเรกทอรี มันเป็นเครื่อง Linux ทั่วไปฉันมี bash shell:

grep -ircl "foo=" *

ในไดเรกทอรีนี้ยังมีไฟล์ไบนารีจำนวนมากที่ตรงกับ "foo =" เนื่องจากผลลัพธ์เหล่านี้ไม่เกี่ยวข้องและทำให้การค้นหาช้าลงฉันต้องการ grep ข้ามการค้นหาไฟล์เหล่านี้ (ส่วนใหญ่เป็นรูป JPEG และ PNG) ฉันจะทำอย่างไร

ฉันรู้ว่ามี--exclude=PATTERNและ--include=PATTERNตัวเลือก แต่รูปแบบรูปแบบคืออะไร หน้า man ของ grep พูดว่า:

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

ค้นหาgrep include , grep include include , grep แยกและตัวแปรไม่พบสิ่งที่เกี่ยวข้อง

หากมีวิธีที่ดีกว่าในการ grepping เฉพาะในไฟล์บางไฟล์ฉันก็พอแล้ว การย้ายไฟล์ที่ละเมิดนั้นไม่ใช่ตัวเลือก ฉันไม่สามารถค้นหาเฉพาะบางไดเรกทอรี (โครงสร้างไดเรกทอรีเป็นระเบียบใหญ่กับทุกสิ่ง) นอกจากนี้ฉันไม่สามารถติดตั้งอะไรได้ดังนั้นฉันต้องทำด้วยเครื่องมือทั่วไป (เช่นgrepหรือการค้นหาที่แนะนำ)


13
เพียง FYI ข้อโต้แย้งที่ใช้: -c นับการจับคู่ในไฟล์ -i case-insensitive -l แสดงเฉพาะไฟล์ที่ตรงกัน -r recursive
Piskvor ออกจากอาคารเมื่อ

68
วิธีที่รวดเร็วในการยกเว้น dirs SVN เป็น--exclude-dir=.svnดังนั้น grep ไม่ได้ไปเข้าพวกเขาทั้งหมด
orip

25
ผู้คนอาจต้องรู้จุดเดินเท้าสองสามข้อ: 1. สังเกตการขาดเครื่องหมายอัญประกาศล้อมรอบที่นี่: --exclude = ' . {png, jpg}' ใช้ไม่ได้ (อย่างน้อยกับรุ่น GNU grep ของฉัน) เพราะ grep ไม่สนับสนุน {} ในความเศร้าโศก ด้านบนคือเชลล์ที่ขยายเป็น '--exclude = .png --exclude = *. jpg' (สมมติว่าไม่มีไฟล์ที่ตรงกับใน cwd - เป็นไปได้ยากมากเนื่องจากคุณไม่ได้เริ่มต้นชื่อไฟล์ด้วย '--exclude =') ซึ่ง grep ชอบสบายดี 2. --Exclude เป็นส่วนขยายของ GNU และไม่ใช่ส่วนหนึ่งของคำจำกัดความของ grep ของ POSIX ดังนั้นหากคุณเขียนสคริปต์โดยใช้สิ่งนี้โปรดทราบว่าพวกเขาไม่จำเป็นต้องทำงานบนระบบที่ไม่ใช่ GNU
ijw

2
ตัวอย่างเต็มรูปแบบของการใช้งานที่ไม่รวม:grep -r --exclude-dir=var "pattern" .
Tisch

คำตอบ:


767

ใช้ไวยากรณ์ globbing เปลือก:

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

ไวยากรณ์สำหรับ--excludeเหมือนกัน

โปรดทราบว่าดาวนั้นได้รับการหลบหนีด้วยแบ็กสแลชเพื่อป้องกันไม่ให้มันถูกขยายโดยเชลล์ (ยกตัวอย่างเช่น --include="*.{cpp,h}"จะทำงานได้ดีเช่นกัน) มิฉะนั้นหากคุณมีไฟล์ใด ๆ ในไดเรกทอรีการทำงานปัจจุบันที่ตรงกับรูปแบบบรรทัดคำสั่งจะขยายออกไปเป็นแบบgrep pattern -r --include=foo.cpp --include=bar.h rootdirที่จะค้นหาเฉพาะไฟล์ที่มีชื่อfoo.cppและbar.hซึ่งค่อนข้างน่าจะไม่ใช่สิ่งที่คุณต้องการ


8
ฉันไม่รู้ว่าทำไม แต่ฉันต้องพูดถึงรูปแบบรวมเช่นนี้:grep pattern -r --include="*.{cpp,h}" rootdir
topek

6
@topek: ข้อดี - ถ้าคุณมีไฟล์. cpp / .h ใด ๆ ในไดเรกทอรีปัจจุบันของคุณเชลล์จะขยาย glob ก่อนที่จะเรียกใช้ grep ดังนั้นคุณจะจบลงด้วยบรรทัดคำสั่งgrep pattern -r --include=foo.cpp --include=bar.h rootdirซึ่งจะค้นหาเฉพาะไฟล์ ชื่อหรือfoo.cpp bar.hหากคุณไม่มีไฟล์ใด ๆ ที่ตรงกับ glob ในไดเรกทอรีปัจจุบันเชลล์จะส่งผ่าน glob ไปยัง grep ซึ่งแปลความหมายได้อย่างถูกต้อง
Adam Rosenfield

6
ฉันเพิ่งรู้ว่า glob นั้นใช้เพื่อจับคู่ชื่อไฟล์เท่านั้น ในการแยกไดเรกทอรีทั้งหมดจำเป็นต้องมี--exclude-dirตัวเลือก กฎเดียวกันใช้แม้ว่า มีการจับคู่ชื่อไฟล์ไดเรกทอรีเท่านั้นไม่ใช่เส้นทาง
Krzysztof Jabłoński

3
--include--excludeดูเหมือนจะไม่ทำงานหลังจากที่ ฉันคิดว่ามันไม่เข้าท่าเลยที่จะลองยกเว้นว่าฉันต้องaliasgrep พร้อมกับรายการที่มีความยาว--excludeและ--exclude-dirซึ่งฉันใช้สำหรับการค้นหารหัสละเว้นไลบรารีและสลับไฟล์และสิ่งต่าง ๆ ฉันจะได้หวังว่าgrep -r --exclude='*.foo' --include='*.bar'จะทำงานเพื่อให้ฉันสามารถ จำกัด ของฉันaliasจะ--include='*.bar'มีเพียง แต่ดูเหมือนจะไม่สนใจ--includeและรวมถึงทุกอย่างที่ไม่ได้เป็นไฟล์ .foo สลับการสั่งซื้อของ--includeและ--excludeการทำงาน aliasแต่อนิจจาที่ไม่เป็นประโยชน์กับฉัน
Michael Scheper

1
เราจะอ่านใจของใครบางคนเพื่อรับกฎนี้PATTERNได้อย่างไร ครึ่งชั่วโมงฉันไม่สามารถหาคำอธิบายใด ๆ ของสิ่งที่พวกเขากำลังรอคอย
Arkady

221

หากคุณต้องการข้ามไฟล์ไบนารีฉันขอแนะนำให้คุณดูที่-Iตัวเลือก (ตัวพิมพ์ใหญ่ i) จะละเว้นไฟล์ไบนารี ฉันใช้คำสั่งต่อไปนี้เป็นประจำ:

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

มันค้นหาแบบวนซ้ำละเว้นไฟล์ไบนารีและไม่ดูภายในโฟลเดอร์ที่ถูกโค่นล้มที่ถูกซ่อนสำหรับรูปแบบใดที่ฉันต้องการ ฉันได้นามแฝงว่า "grepsvn" บนกล่องในที่ทำงาน


1
ขอบคุณนั่นมีประโยชน์มากสำหรับสถานการณ์อื่น ๆ ที่ฉันเคยพบมา
Piskvor ออกจากอาคาร

25
--exclude-dirไม่สามารถใช้ได้ทุกที่ กล่อง RH ของฉันที่ทำงานกับ GNU grep 2.5.1 ไม่มีอยู่
gcb

คำแนะนำสำหรับสิ่งที่จะใช้เมื่อ--exclude-dirไม่พร้อมใช้งาน? ในความพยายามทั้งหมดของฉัน--excludeดูเหมือนจะไม่พอดีกับใบเรียกเก็บเงิน
JMTyler

คุณสามารถดาวน์โหลดแหล่ง grep ล่าสุดจาก GNU ได้ตลอดเวลาและทำการกำหนดค่า ทำให้; sudo ทำการติดตั้ง ' นี่เป็นหนึ่งในสิ่งแรกที่ฉันทำบน Mac หรือการแจกจ่าย Linunx รุ่นเก่า
Jonathan Hartley

3
สิ่งที่ฉันต้องการ จริงๆแล้วฉันใช้คอมไพล์ --exclude-dir="\.git"ดังนั้น :-)
IonicăBizău

66

โปรดดูackซึ่งได้รับการออกแบบมาสำหรับสถานการณ์เหล่านี้ ตัวอย่างของคุณ

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

เสร็จสิ้นด้วย ack as

ack -icl "foo="

เนื่องจาก ack ไม่เคยดูในไฟล์ไบนารีโดยค่าเริ่มต้นและ -r เปิดอยู่ตามค่าเริ่มต้น และถ้าคุณต้องการเฉพาะไฟล์ CPP และ H ให้ทำ

ack -icl --cpp "foo="

ดูดีจะลองรุ่น Perl แบบสแตนด์อโลนในครั้งต่อไปขอบคุณ
Piskvor ออกจากอาคารใน

5
เป็นการโทรที่ดีฉันไม่สามารถอยู่ได้โดยปราศจากการตอบรับ
โอกาส

1
stackoverflow.com/questions/667471/… - สิ่งนี้จะช่วยให้คุณได้รับ ack บน windows หากเป็นที่ที่คุณใช้ grep
TamusJRoyce

@Chance บางทีคุณอาจต้องการsilversearcher-AGเพียงapt-getในอูบุนตู :)
Justme0

เพื่อไม่ให้สับสนกับawk
jasonleonhard

35

grep 2.5.3 แนะนำพารามิเตอร์ --exclude-dir ซึ่งจะทำงานในแบบที่คุณต้องการ

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

นอกจากนี้คุณยังสามารถตั้งค่าตัวแปรสภาพแวดล้อม: GREP_OPTIONS = "--lude-dir = .svn"

ฉันจะสองของแอนดี้คะแนนสำหรับแอ๊แม้ว่ามันที่ดีที่สุด


7
+1 สำหรับพูดถึงหมายเลขรุ่นที่แน่นอน; ฉันมี grep 2.5.1 และตัวเลือกการแยกไม่สามารถใช้งานได้
James

25

ฉันพบสิ่งนี้หลังจากใช้เวลานานคุณสามารถเพิ่มการรวมหลายรายการและไม่รวมเช่น:

grep "z-index" . --include=*.js --exclude=*js/lib/* --exclude=*.min.js

5
มันจะดีกว่าที่จะรวมพวกเขาในรายการเช่น: --exclude = {pattern1, pattern2, pattern3}
Yasser Sinjab

12

คำสั่งที่แนะนำ:

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

เป็นแนวคิดที่ผิดเพราะ - ยกเว้นงานบนฐาน กล่าวอีกนัยหนึ่งมันจะข้ามเฉพาะ. svn ในไดเรกทอรีปัจจุบัน


3
ใช่มันไม่ทำงานเลยสำหรับฉัน สิ่งที่ใช้ได้ผลสำหรับฉันคือ: excluse-dir = .svn
Taryn East

2
@Nicola ขอบคุณ! ฉันฉีกขาดเกี่ยวกับสาเหตุที่ทำให้สิ่งนี้ไม่ทำงาน บอกฉันมีวิธีที่จะค้นพบสิ่งนี้จาก manpage หรือไม่? ทั้งหมดบอกว่ามันตรงกับ "รูปแบบ" แก้ไข manpage บอกว่า "file" ตามที่อธิบายไว้ที่นี่fixunix.com/unix/…
13ren

11

ใน grep 2.5.1 คุณต้องเพิ่มบรรทัดนี้ไปยังโปรไฟล์ ~ / .bashrc หรือ ~ / .bash

export GREP_OPTIONS="--exclude=\*.svn\*"

9

ฉันพบว่าการพิมพ์ grep grep ของ grep มีประโยชน์มากในบางครั้ง:

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

ถึงแม้ว่านั่นจะไม่ได้หยุดมันจากการค้นหาไฟล์ไบนารี


10
คุณสามารถใช้grep -Iเพื่อข้ามไฟล์ไบนารี
Nathan Fellman

ได้ทำเช่นนั้นเมื่อตอนที่ฉันยังเป็นเด็ก ... ตอนนี้ฉันรู้ดีขึ้นและเมื่อเผชิญหน้ากับปัญหาสิ่งแรกคือ RTFM
gcb

grep grep จะลบไฮไลท์สีออก
Max Li

7

หากคุณไม่รังเกียจที่จะใช้findฉันชอบ-pruneคุณสมบัติของมัน:

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

ในบรรทัดแรกคุณระบุไดเรกทอรีที่คุณต้องการค้นหา .(ไดเรกทอรีปัจจุบัน) เป็นเส้นทางที่ถูกต้องตัวอย่างเช่น

เมื่อวันที่ 2 และสาย 3, การใช้งาน"*.png", "*.gif", "*.jpg"และอื่น ๆ ใช้โครงสร้างเหล่านี้มาก-o -name "..." -pruneเท่าที่คุณมีรูปแบบ

ในบรรทัดที่ 4 คุณต้องการอีกบรรทัด -o (มันระบุ "หรือ" ถึงfind), รูปแบบที่คุณต้องการและคุณต้องการ a -printหรือ-print0ที่ส่วนท้ายของมัน ถ้าคุณเพียงต้องการ "ทุกสิ่งทุกอย่าง" ที่ยังคงอยู่หลังจากการตัดแต่งกิ่ง*.gif, *.pngฯลฯ ภาพแล้วใช้ -o -print0และคุณกำลังทำกับเส้นที่ 4

ในที่สุดบนบรรทัดที่ 5 คือไพพ์xargsที่ใช้แต่ละไฟล์ที่เกิดขึ้นและเก็บไว้ในตัวแปรFILENAMEซึ่งจะใช้เวลาแต่ละไฟล์ที่เกิดเหล่านั้นและเก็บไว้ในตัวแปรจากนั้นก็ผ่านธงที่แล้วมีการขยายตัวที่จะกลายเป็นรายการชื่อไฟล์ที่พบโดยgrep-IR"pattern"FILENAMExargsfind

สำหรับคำถามเฉพาะของคุณข้อความดังกล่าวอาจมีลักษณะดังนี้:

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


หนึ่งการแก้ไขที่ฉันแนะนำ: รวม-falseทันทีหลังจาก-pruneนั้นจึงลืมใช้-print0หรือexecคำสั่งบางประเภทจะไม่พิมพ์ไฟล์ที่คุณต้องการยกเว้น: -name "*.png" -prune -false -o name "*.gif -prune -false...
OnlineCop

7

บน CentOS 6.6 / Grep 2.6.3 ฉันต้องใช้สิ่งนี้:

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

สังเกตเห็นการขาดเครื่องหมายเท่ากับ "=" (ไม่--includeเช่น--excludeนั้นinclude-dirและ--exclude-dirจะถูกละเว้น)


6

git grep

ใช้git grepซึ่งปรับให้เหมาะสมสำหรับประสิทธิภาพและมีเป้าหมายเพื่อค้นหาไฟล์บางไฟล์

.gitignoreโดยค่าเริ่มต้นจะละเว้นไฟล์ไบนารีและเป็นที่เคารพของคุณ หากคุณไม่ได้ทำงานกับโครงสร้าง Git คุณยังสามารถใช้งานได้โดยผ่าน--no-indexคุณยังสามารถใช้งานได้โดยผ่าน

ไวยากรณ์ตัวอย่าง:

git grep --no-index "some_pattern"

ดูตัวอย่างเพิ่มเติมได้ที่:


5

ฉันเป็นคนใจร้อนได้รับสิทธิ์ แต่นี่คือลักษณะของฉัน / .bash_profile:

ส่งออก GREP_OPTIONS = "- orl --exclude-dir = .svn --exclude-dir = .cache --color = auto" GREP_COLOR = '1; 32'

โปรดทราบว่าในการยกเว้นสองไดเรกทอรีฉันต้องใช้ --exclude-dir สองครั้ง


3

ลองอันนี้:

$ ค้นหา -name "* .txt" -type f -print | ไฟล์ xargs | grep "foo =" | ตัด -d: -f1

ก่อตั้งขึ้นที่นี่: http://www.unix.com/shell-programming-scripting/42573-search-files-excluding-binary-files.html


3
สิ่งนี้ใช้ไม่ได้กับชื่อไฟล์ที่มีช่องว่าง แต่ปัญหานั้นสามารถแก้ไขได้อย่างง่ายดายโดยใช้ print0 แทนที่จะพิมพ์และเพิ่มตัวเลือก -0 ให้กับ xargs
Adam Rosenfield

3

หากคุณค้นหาแบบไม่วนซ้ำคุณสามารถใช้รูปแบบ Glopเพื่อจับคู่ชื่อไฟล์

grep "foo" *.{html,txt}

รวมถึง html และ txt มันค้นหาในไดเรกทอรีปัจจุบันเท่านั้น

วิธีค้นหาในไดเรกทอรีย่อย:

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

ในไดเรกทอรีย่อย:

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

3

ในไดเรกทอรีนี้ยังมีไฟล์ไบนารีจำนวนมาก ฉันไม่สามารถค้นหาเฉพาะบางไดเรกทอรี (โครงสร้างไดเรกทอรีเป็นระเบียบใหญ่) มีวิธีที่ดีกว่าในการ grepping เฉพาะในไฟล์บางไฟล์?

ripgrep

นี่เป็นหนึ่งในเครื่องมือที่เร็วที่สุดที่ออกแบบมาเพื่อค้นหาไดเรกทอรีปัจจุบันของคุณซ้ำ มันถูกเขียนขึ้นในRustสร้างขึ้นจากเครื่องยนต์ regex ของ Rustเพื่อประสิทธิภาพสูงสุด ตรวจสอบการวิเคราะห์รายละเอียดที่นี่การวิเคราะห์รายละเอียดที่นี่

ดังนั้นคุณสามารถเรียกใช้:

rg "some_pattern"

มันเคารพคุณ .gitignoreและข้ามไฟล์ / ไดเรกทอรีและไฟล์ไบนารีที่ซ่อนอยู่โดยอัตโนมัติ

คุณยังสามารถปรับแต่งรวมหรือไม่รวมไฟล์และไดเรกทอรีใช้/-g --globกฎ Globbing จับคู่.gitignoreglobs ตรวจสอบman rgความช่วยเหลือ

สำหรับตัวอย่างเพิ่มเติมให้ดูที่: วิธีการยกเว้นบางไฟล์ที่ไม่ตรงกับส่วนขยายบางอย่างด้วย grep

บน MacOS brew install ripgrepคุณสามารถติดตั้งผ่านทาง


3

find และ xargs เป็นเพื่อนของคุณ ใช้พวกมันเพื่อกรองรายการไฟล์แทน grep's --exclude

ลองสิ่งที่ชอบ

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

ข้อดีของการทำความคุ้นเคยกับสิ่งนี้คือมันสามารถขยายไปยังกรณีการใช้งานอื่น ๆ ตัวอย่างเช่นการนับบรรทัดในไฟล์ที่ไม่ใช่ png ทั้งหมด:

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

หากต้องการลบไฟล์ที่ไม่ใช่ png ทั้งหมด:

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

เป็นต้น

ตามที่ระบุไว้ในความคิดเห็นหากไฟล์บางไฟล์อาจมีช่องว่างในชื่อให้ใช้-print0และxargs -0แทน


1
สิ่งนี้ใช้ไม่ได้กับชื่อไฟล์ที่มีช่องว่าง แต่ปัญหานั้นสามารถแก้ไขได้อย่างง่ายดายโดยใช้ print0 แทนที่จะพิมพ์และเพิ่มตัวเลือก -0 ให้กับ xargs
Adam Rosenfield

2

สคริปต์เหล่านั้นไม่สามารถแก้ปัญหาทั้งหมดได้ ... ลองวิธีนี้ให้ดีกว่า:

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

สคริปต์นี้ดีกว่าเพราะใช้นิพจน์ทั่วไป "ของจริง" เพื่อหลีกเลี่ยงไดเรกทอรีจากการค้นหา เพียงแยกชื่อโฟลเดอร์หรือไฟล์ด้วย "\ |" บน grep -v

สนุกกับมัน! พบได้บนเปลือก linux ของฉัน! XD


2

ดู @ อันนี้

grep --exclude="*\.svn*" -rn "foo=" * | grep -v Binary | grep -v tags

2
สิ่งที่ได้รับประมาณนี้ถูกโพสต์ในโพสต์อื่น; ยิ่งไปกว่านั้นสิ่งนี้เป็นสิ่งผิดปกติด้วยการที่ตัวเลือกเลย์เอาต์ต่างๆตั้งค่ามันจะทำให้จำนวนบรรทัดและสิ่งต่าง ๆ เช่นหรือแยกบรรทัดบริบทที่ต้องการ
Chris Morgan

คุณจะใช้ตัวเลือก "-v" หลายตัวพร้อมกันได้อย่างไร?
เปิดทาง

1

--binary-files=without-matchตัวเลือกที่จะ GNU grepได้รับมันจะข้ามไฟล์ไบนารี เทียบเท่ากับ-Iสวิตช์ที่กล่าวถึงที่อื่น)

(สิ่งนี้อาจต้องใช้เวอร์ชันล่าสุดที่grep2.5.3 เป็นอย่างน้อย)


1

เหมาะสำหรับไฟล์ tcsh .alias:

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

เอาฉันสักครู่เพื่อหาว่าส่วน {mm, m, h, cc, c} ไม่ควรอยู่ในเครื่องหมายคำพูด ~ คี ธ


0

หากต้องการละเว้นผลลัพธ์ไบนารีทั้งหมดจาก grep

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

ส่วน awk จะกรองไฟล์ Binary ทั้งหมดที่ตรงกับบรรทัด


-2

ลองสิ่งนี้:

  1. สร้างโฟลเดอร์ชื่อ " --F" ภายใต้ currdir .. (หรือเชื่อมโยงโฟลเดอร์อื่นมีเปลี่ยนชื่อเป็น " --F" double-minus-Fคือ
  2. #> grep -i --exclude-dir="\-\-F" "pattern" *
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.