ฉันกำลังค้นหาการประกาศคลาสบนไซต์ที่มีไฟล์ PHP หลายร้อยไฟล์ ฉันจะทำสิ่งนี้ในโฟลเดอร์ปัจจุบันและโฟลเดอร์ย่อยโดยใช้grep ได้อย่างไร
ฉันทดสอบcd
ไอเอ็นจีไปยังโฟลเดอร์และจากนั้นสิ่งที่ชอบ
grep -r 'class MyClass' *.php
ฉันกำลังค้นหาการประกาศคลาสบนไซต์ที่มีไฟล์ PHP หลายร้อยไฟล์ ฉันจะทำสิ่งนี้ในโฟลเดอร์ปัจจุบันและโฟลเดอร์ย่อยโดยใช้grep ได้อย่างไร
ฉันทดสอบcd
ไอเอ็นจีไปยังโฟลเดอร์และจากนั้นสิ่งที่ชอบ
grep -r 'class MyClass' *.php
คำตอบ:
ฉันขอแนะนำให้คุณใช้งานctagsแทนการใช้ grep อย่างไรก็ตามถ้าคุณต้องการคุณสามารถทำสิ่งที่ชอบ
find <top level dir> -name \*.php | xargs grep "class MyClass"
แน่นอนว่าคุณมีช่องว่างระหว่างclass
และmyClass
ที่อาจไม่เป็นจริง มันง่ายที่จะเปลี่ยน regexp เพื่อค้นหาช่องว่างจำนวนเท่าใดก็ได้
หากคุณใช้-r
คุณอาจต้องการค้นหาซ้ำในไดเรกทอรีปัจจุบันซ้ำ:
grep -r 'class MyClass' .
หมายเหตุช่วงเวลาในตอนท้ายของข้างต้น
สิ่งที่คุณบอกgrep
คือคุณต้องการให้มันทำการค้นหา*.php
ไฟล์หรือไดเรกทอรีซ้ำทุกครั้งแต่คุณอาจไม่มีไดเรกทอรีที่ลงท้ายด้วยนามสกุล. php ด้านบนเป็นวิธีที่ง่ายที่สุดในการค้นหา แต่ยังรวมถึงไฟล์ประเภทอื่น ๆ ซึ่งเป็นปัญหาโดยเฉพาะอย่างยิ่งเมื่อคุณมีไดเรกทอรี. svn อยู่ทุกที่ หากคุณไม่มีไฟล์ประเภทอื่น ๆ จำนวนมากดังกล่าวข้างต้นโดยทั่วไปเพียงพอและทำงานได้ดี
ส่วนใหญ่ของ grep ไม่มีวิธีระบุนามสกุลไฟล์ที่สามารถค้นหาได้ดังนั้นโดยทั่วไปแล้วคุณใช้ find ร่วมกับมัน:
find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} \;
-iname
บอก grep บางเวอร์ชันว่าคุณต้องการทำการค้นหาชื่อไฟล์โดยไม่ต้องคำนึงถึงตัวพิมพ์เล็กและตัวพิมพ์ใหญ่ แต่ไม่ใช่ใน GNU รุ่นต่างๆที่ไม่รองรับการค้นหาดังนั้นคุณสามารถใช้-name
แทนได้
-exec
ตัวเลือกดังกล่าวข้างต้นมีผลข้างเคียงของการเรียก grep สำหรับทุกไฟล์ซึ่งเป็นค่าใช้จ่ายที่เป็นธรรม
ยังรุ่นอื่น ๆ ของ grep สนับสนุน+
ที่บอกให้พบการผนวกข้อโต้แย้งเข้าด้วยกันเพื่อลดจำนวนการเรียกใช้ของการปฏิบัติการ:
find <startDir> -iname '*.php' -exec grep 'class[ \t]*MyClass' {} + \;
วิธีที่แนะนำให้ใช้บ่อยเพื่อลดการเรียกใช้คือการใช้ xargs ซึ่งจะทำการไล่ grep ออกให้น้อยที่สุดเท่าที่จะทำได้ แต่ให้มากที่สุดเท่าที่จำเป็น:
find <startDir> -iname \*.php | xargs grep "class[ \t]*MyClass"
xargs
ฉลาดพอที่จะส่ง grep จนถึงจำนวนอาร์กิวเมนต์สูงสุดที่สนับสนุนในบรรทัดคำสั่ง แต่รูปแบบข้างต้นไม่รองรับอักขระบางตัวเช่นช่องว่างได้ดี ตัวอย่างเช่นมี 'the file.php' ชื่อไฟล์ grep จะได้รับ 'the' เป็นอาร์กิวเมนต์และ 'file.php' เป็นอาร์กิวเมนต์ดังนั้นทั้งคู่จะไม่พบ เราใช้แทน:
find <startDir> -iname \*.php -print0 | xargs -0 grep "class[ \t]*MyClass"
print0
และ-0
ทำงานร่วมกันและใช้อาร์กิวเมนต์ตามด้วยอักขระ null เพื่อให้อาร์กิวเมนต์มีการระบุอย่างสมบูรณ์และชัดเจน
ถ้าคุณมีช่องว่างมากกว่าหนึ่งหลังclass
หรือแท็บคุณอาจต้องการอนุญาตให้ใช้อักขระเพิ่มเติมโดยเปลี่ยน regex:class[ \t]*MyClass
โพสต์บน StackOverflow มีตัวอย่างอื่นและแสดงวิธีแยกไดเรกทอรีบางรายการเช่นไดเรกทอรี. svn
การใช้ที่ยอดเยี่ยมที่เคยแอ๊ ,
ack --php 'class MyClass'
grep -r 'class MyClass' *.php
จะค้นหาโฟลเดอร์ทั้งหมดที่มีชื่อลงท้ายด้วย. php
grep -r 'class MyClass' . | grep .php
จะค้นหาคลาส MyClass ในไฟล์ทั้งหมดในโฟลเดอร์ย่อยทั้งหมดจากนั้นส่งคืนเฉพาะไฟล์ที่มี. php อยู่เท่านั้น
find . -type f -name *.php -print -exec grep \"class MyClass\" {} \;
จะให้เนื้อหาของบรรทัดที่พบในและเส้นทางไปยังไฟล์
ในกรณีที่ไฟล์ที่จับคู่อาจมีชื่อโดยพลการคุณควรพิจารณาใช้ -print0
หา -type f -name '* .php' -print0 | xargs -0 grep 'class MyClass'
grep -rl 'class MyClass' . --include \*.php
l แสดงชื่อไฟล์เท่านั้น
r คือ recurive
. ค้นหาในโฟลเดอร์ปัจจุบัน
- รวมส่วนขยายของชื่อไฟล์ที่ จำกัด
อาจเป็นเพราะคุณต้องการตัวพิมพ์เล็กและตัวพิมพ์เล็กและช่องว่างที่ยอมรับได้และ grep จะยุติหากไม่พบอินสแตนซ์ของรูปแบบไฟล์ที่ต้องการในไดเรกทอรีปัจจุบัน จำเป็นต้องทราบว่าจะเริ่มต้นอย่างไรและไม่มีไฟล์ใดที่ตรงกับการผลิตจึงไม่มีเส้นทางเริ่มต้น
หากมีนามสกุลไฟล์ที่ต้องการอย่างน้อยหนึ่งไฟล์คุณสามารถใช้ egrep -ir find
และxargs
แสดงพลังของพวกเขาด้วยไดเรกทอรีเดียว (แต่ใหญ่มาก) ที่ grep ล้มเหลวและมีคุณสมบัติเพิ่มเติม (ตัวอย่างเช่นหากคุณต้องการค้นหาไฟล์. inc, .php และ php3 เท่านั้น) แต่มันเสียความสะดวกและความเร็วไปเล็กน้อยในประสบการณ์ของฉัน สำหรับการประกาศในชั้นเรียนของมนุษย์เป็นปัญหาใหญ่ที่จะเป็นช่องว่าง ดังนั้นใช้ egrep แทน grep นอกจากนี้ LC_ALL = C สำหรับความเร็วพิเศษ เพื่อความสะดวกฉันมักจะใช้:
LC_ALL=C egrep -irn "class[ ]*myclass([ ]|\n)" * | egrep "\.(inc|php[35]?)"
-i -- case insensitive
-r -- recursive for all file pattern (here *)
-n -- include the line number
LC_ALL=C -- search in ASCII, not in utf8, this is much faster.
[ ]* -- match any number of spaces before the class name
([ ]|\n) -- match a space or newline after the classname
สิ่งนี้ยังคงสามารถจับคู่ความคิดเห็นเช่น// class myclass exists in file
แต่ฉันพบว่ามีขนาดค่อนข้างเล็กและสามารถกรองออกด้วย... | fgrep -v '//'
คุณสามารถรวมรูปแบบไฟล์ที่ซับซ้อนมากขึ้น (เช่นเพื่อจับไฟล์. inc และ. php ส่วนใหญ่) ในรูปแบบไฟล์ egrep ดังนี้:
egrep "pattern" *.[ip]*
(พร้อมตัวเลือกแรก) นั้นจะค่อนข้างเร็วและ จำกัด อยู่ที่ไฟล์ php เป็นส่วนใหญ่
HTH
ฉันรู้ว่ามันบอกว่าใช้grep
แต่สิ่งที่ฉันชอบคือack-grep
:
ack-grep "class MyClass"
การดำเนินการนี้จะวนซ้ำแสดงชื่อไฟล์ที่พบผลลัพธ์พร้อมหมายเลขบรรทัดตามที่พบและไฮไลต์ ในการกำหนดเป้าหมายไฟล์ php โดยเฉพาะคุณสามารถเรียกใช้:
ack-grep --type-set php:ext:php "path"
แพ็คเกจนี้มีตัวเลือกให้เลือกมากมาย; ฉันขอแนะนำอย่างแน่นอน (และเรียกดูหน้าเว็บที่เกี่ยวข้อง) เพื่อทำสิ่งที่แฟนซี
grep -r
ไม่ได้ให้