ฉันจะใช้ตัวเลือก grep --include สำหรับไฟล์หลายประเภทได้อย่างไร


100

เมื่อฉันต้องการ grep ไฟล์ html ทั้งหมดในบางไดเร็กทอรีฉันทำสิ่งต่อไปนี้

grep --include="*.html" pattern -R /some/path

ซึ่งทำงานได้ดี ปัญหาคือจะ grep ไฟล์ html, htm, php ทั้งหมดในบางไดเร็กทอรีได้อย่างไร?

จากสิ่งนี้Use grep --exclude / - include syntax to not grep through some filesดูเหมือนว่าฉันสามารถทำสิ่งต่อไปนี้ได้

grep --include="*.{html,php,htm}" pattern -R /some/path

แต่น่าเศร้าที่มันไม่ได้ผลสำหรับฉัน
FYI เวอร์ชัน grep ของฉันคือ 2.5.1

คำตอบ:


143

คุณสามารถใช้--includeแฟล็กหลาย ๆ สิ่งนี้ใช้ได้กับฉัน:

grep -r --include=*.html --include=*.php --include=*.htm "pattern" /some/path/

อย่างไรก็ตามคุณสามารถทำได้ตามที่Deruijterแนะนำ สิ่งนี้ใช้ได้กับฉัน:

grep -r --include=*.{html,php,htm} "pattern" /some/path/

อย่าลืมว่าคุณสามารถใช้findและxargsสำหรับสิ่งนี้เพื่อ:

find /some/path/ -name "*.htm*" -or -name "*.php" | xargs grep "pattern"

HTH


1
ฉันเห็นปัญหา ฉันใช้ --include = " . {html, php}" เพื่อป้องกันไม่ให้เชลล์ขยาย ' ' ซึ่งในขณะเดียวกันก็หยุดเชลล์เพื่อขยาย {html, php} ดูเหมือนว่าการลงชื่อเข้าใช้เท่ากับ --include = * จะสามารถป้องกันไม่ให้เชลล์ขยาย '*' ได้
tianyapiaozi

xargs ไม่ใช่สิ่งทดแทนจริงๆ หลายครั้งที่คุณต้องการคุณสมบัตินี้คุณกำลังจัดการกับไฟล์มากกว่า xargs จะจัดการได้
James Moore

2
@JamesMoore: ลองดูที่GNU ขนาน มักจะใช้แทนxargs. นี้ยังเป็นมูลค่าการอ่านอย่างรวดเร็ว HTH.
Steve

3
@tianyapiaozi: คุณถูกต้องที่การอ้างถึงรอบการขยายตัวของวงเล็บปีกกาเป็นปัญหา โดยไม่ต้องอ้าง แต่*ยังคงเป็นเรื่องที่จะ globbing เป็นส่วนหนึ่งของโทเค็นมันฝังอยู่ในมันก็เกิดขึ้นไม่ได้จะมีการแข่งขันอะไรในกรณีนี้เพราะเพียงไฟล์ตัวอักษรบางสิ่งบางอย่างที่มีชื่อเหมือน--include=foo.htmlจะตรงกับ เพื่อความปลอดภัยให้อ้างอิง*(ซึ่งคุณสามารถทำได้ทีละรายการด้วย\*) ในฐานะที่เป็นโบนัสเพิ่มเติมสิ่งนี้ทำให้มองเห็นได้ชัดเจนขึ้นซึ่งไม่ใช่เปลือกที่ควรทำในกรณีนี้
mklement0

2
สำหรับfindวิธีแก้ปัญหา: การใช้-exec grep "pattern" {} +แทน| xargs grep "pattern"จะมีประสิทธิภาพมากกว่า (เช่นจัดการชื่อไฟล์ที่มีช่องว่างเป็นต้น) และมีประสิทธิภาพมากขึ้น
mklement0

32

ใช้{html,php,htm}เพียงสามารถทำงานเป็นขยายตัวรั้งซึ่งเป็นมาตรฐานคุณลักษณะ (ไม่ POSIX สอดคล้อง) ของbash, และkshzsh

  • กล่าวอีกนัยหนึ่ง: อย่าพยายามใช้ในสคริปต์ที่กำหนดเป้าหมาย/bin/sh- ใช้อาร์กิวเมนต์ที่ชัดเจนหลายรายการ--includeในกรณีนั้น

  • grepตัวเองไม่เข้าใจ{...}สัญกรณ์

สำหรับการขยายตัวรั้งที่จะได้รับการยอมรับก็ต้องเป็นunquoted (ส่วนหนึ่งของ) tokenในบรรทัดคำสั่ง

การขยายวงเล็บปีกกาจะขยายไปยังอาร์กิวเมนต์หลายตัวดังนั้นในกรณีที่อยู่ในมือgrepจะเห็นหลาย --include=...ตัวเลือกเหมือนกับว่าคุณส่งผ่านทีละข้อ

ผลลัพธ์ของการขยายวงเล็บปีกกาขึ้นอยู่กับ globbing (การขยายชื่อไฟล์)ซึ่งมีข้อผิดพลาด :

  • แต่ละข้อโต้แย้งที่เกิดสามารถต่อขยายได้ถึงชื่อไฟล์ที่ตรงกันถ้ามันเกิดขึ้นจะมีunquoted metacharacters globbing *เช่น
    แม้ว่าสิ่งนี้จะไม่น่าเกิดขึ้นกับโทเค็นเช่น--include=*.html(เช่นคุณต้องมีไฟล์ที่ตั้งชื่อตามตัวอักษรเช่น--include=foo.htmlเพื่อให้ตรงกัน) แต่ก็ควรคำนึงถึงโดยทั่วไป

  • ถ้าnullglobตัวเลือกเปลือกเกิดขึ้นจะเปิด ( shopt -s nullglob) และ globbing การแข่งขันอะไรอาร์กิวเมนต์จะถูกทิ้ง

ดังนั้นสำหรับโซลูชันที่มีประสิทธิภาพเต็มที่ให้ใช้สิ่งต่อไปนี้:

grep -R '--include=*.'{html,php,htm} pattern /some/path
  • '--include=*.'จะถือว่าเป็นตัวอักษรเนื่องจากจะเป็นคนเดียวที่ยกมา ; สิ่งนี้จะป้องกันการตีความโดยไม่ได้ตั้งใจ*ว่าเป็นตัวละครที่มีลักษณะกลม

  • {html,php,htm}ที่ - ความจำเป็น - unquotedขยายตัวรั้ง[1] , ขยายไป3ข้อโต้แย้งที่เกิดจากการ{...} โดยตรงต่อไปนี้'...'โทเค็น , รวมถึงโทเค็นว่า

  • ดังนั้นหลังจากลบเครื่องหมายคำพูดโดยเชลล์แล้วอาร์กิวเมนต์ตัวอักษร3 ตัวต่อไปนี้จะถูกส่งไปยัง grep :

    • --include=*.html
    • --include=*.php
    • --include=*.htm

[1] แม่นยำยิ่งขึ้นเป็นเพียงส่วนที่เกี่ยวข้องกับไวยากรณ์ของการขยายวงเล็บปีกกาเท่านั้นที่ต้องไม่ใส่เครื่องหมายคำพูดองค์ประกอบรายการอาจยังคงถูกยกมาทีละรายการและต้องเป็นหากองค์ประกอบเหล่านี้มีอักขระเมตาชาร์กที่อาจทำให้เกิดการโกลว์ที่ไม่ต้องการหลังจากการขยายวงเล็บปีกกา ในขณะที่ไม่จำเป็นในกรณีนี้สามารถเขียนข้างต้นเป็น
'--include=*.'{'html','php','htm'}


1
ขอบคุณมากสำหรับกระทู้นี้ โพสต์ดีๆไม่เพียง แต่ตอบคำถาม แต่ยังสอนสิ่งใหม่ ๆ ให้คุณอีกด้วย! สิ่งนี้มีประโยชน์อย่างยิ่งสำหรับพวกเราที่เขียนสิ่งที่ต้องสอดคล้องกับ POSIX ทุกคนที่ใช้ Mac OS X ควรดูที่นี่!
sabalaba

@sabalaba: ฉันดีใจที่ได้ยิน แต่ชัดเจน: ในขณะที่การขยายวงเล็บปีกกาไม่เป็นไปตาม POSIX แต่ก็ใช้ได้กับbashทุกแพลตฟอร์มที่bashทำงานบน
mklement0

9

ลองลบเครื่องหมายคำพูดคู่

grep --include=*.{html,php,htm} pattern -R /some/path

1
@tianyapiaozi ลองดูgrep --include=\*.{html,php,htm} pattern -R /some/path. มันได้ผลสำหรับฉัน
Hyunjun Kim


2

ลองทำตามนี้ -r จะทำการค้นหาแบบวนซ้ำ -s จะระงับข้อผิดพลาดที่ไม่พบไฟล์ -n จะแสดงหมายเลขบรรทัดของไฟล์ที่พบรูปแบบ

    grep "pattern" <path> -r -s -n --include=*.{c,cpp,C,h}

นี่เป็นคำตอบที่ดีที่สุดสำหรับฉันโดยเฉพาะและฉันคิดว่าคุณสามารถใส่ -rsn แทน -r -s -n ได้ (แต่นั่นคือ nitpicking)
สลิม

ฉันมักจะใช้-rns เพื่อความชัดเจนในตัวอย่างฉันต้องพูดถึง-r -n -s :-) ดีใจที่มันช่วยได้
ประทีป

ฉันขอแนะนำให้เพิ่ม-Iลงในชุดมาตรฐาน มันข้ามไฟล์ไบนารี (ซึ่งแทบจะไม่เคยค้นหาเลย) จึงช่วยเพิ่มประสิทธิภาพ ถ้าอย่างนั้นเราก็ไปgrep -rIns ...เล่นอะคูสติกกันดีกว่า :)
bloody


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