มีวิธีที่ง่ายกว่าในการ grep ไฟล์ทั้งหมดภายใต้ไดเรกทอรีหรือไม่?


21

เมื่อฉันต้องการค้นหาเนื้อหาทั้งหมดฉันจะใช้ต้นไม้

find . -type f -print0 | xargs -0 grep <search_string>

มีวิธีที่ดีกว่าในการทำเช่นนี้ในแง่ของประสิทธิภาพหรือความกะทัดรัด?


2
@Downvoter: ยินดีที่จะปรับปรุงคำถามนี้หากคุณสามารถแบ่งปันความกังวลของคุณ
Dancrumb

2
find find หลายเวอร์ชันมี xargs อยู่ภายใน: find -type f -exec fgrep <search_string> {} +
simpleuser

คำตอบ:


42

ตรวจสอบว่าคุณgrepสนับสนุน-rตัวเลือก (สำหรับrecurse ):

grep -r <search_string> .

1
ใช่ ... ฉันเพิ่งค้นพบstackoverflow.com/questions/16956810/…และนั่นก็เป็นคำตอบที่นั่นด้วย
Dancrumb

เพิ่มความคิดเห็นเกี่ยวกับ--exclude-dirที่อยู่ประสิทธิภาพและเรามีผู้ชนะ!
Dancrumb

1
เพิ่งสังเกตเห็นว่านี่ไม่ใช่การพกพา แต่grepใน FreeBSD และ Linux distros ล่าสุดสนับสนุน แล้วทำไม--exclude-dirล่ะ? คุณไม่ได้ขอให้ค้นหาต้นไม้ทั้งต้นใช่ไหม
Philippos

จุดประสงค์ ... --exclude-dirมีประโยชน์จริง ๆ ในกรณีการใช้งานของฉัน (เนื่องจากส่วนย่อยของต้นไม้มีขนาดใหญ่ แต่ไร้ประโยชน์) และฉันถามเกี่ยวกับประสิทธิภาพ ... แต่คุณพูดถูกมันไม่จำเป็น
Dancrumb

ในกรณีนี้ผมต้องเพิ่มว่า IIRC --exclude-dirเป็นเอกสิทธิ์ของ grepGNU (-:
Philippos

13

คำตอบที่ดีที่สุดย่อย: แทนที่จะท่อส่งออกของfindเข้าgrepคุณสามารถเรียกใช้เพียง

find . -type f -exec grep 'research' {} '+'

และ voila คำสั่งเดียวแทนที่จะเป็นสองคำสั่ง!

คำอธิบาย:

find . -type f

ค้นหาไฟล์ปกติทั้งหมดภายใน

-exec grep 'research'

grep 'การวิจัย'

{}

ในชื่อไฟล์ที่พบ

'+'

ใช้หนึ่งคำสั่งต่อชื่อไฟล์ทั้งหมดไม่ใช่หนึ่งครั้งต่อชื่อไฟล์

Nb: ด้วย';'ชื่อไฟล์ต่อหนึ่งครั้ง

นอกเหนือจากนั้นหากคุณใช้ในการประมวลผลซอร์สโค้ดคุณอาจมองเข้าไปackซึ่งทำเพื่อค้นหาบิตรหัสได้อย่างง่ายดาย

แอ๊กชั่น

แก้ไข:

คุณสามารถขยายการวิจัยออกไปเล็กน้อย ก่อนอื่นคุณสามารถใช้-name ''สวิตช์ของfindเพื่อค้นหาไฟล์ที่มีรูปแบบการตั้งชื่อแบบเฉพาะเจาะจง

ตัวอย่างเช่น

  • ไฟล์ที่สอดคล้องกับบันทึกเท่านั้น: -name '*.log'

  • เฉพาะไฟล์ที่ตรงกับส่วนหัว c แต่คุณไม่สามารถใช้ตัวพิมพ์ใหญ่หรือตัวพิมพ์เล็กสำหรับส่วนขยายชื่อไฟล์ของคุณ: -iname *.c

หมายเหตุ: เหมือนgrepและackที่-iสวิทช์หมายถึงกรณีตายในกรณีนี้

ในกรณีนั้น grep จะแสดงโดยไม่มีสีและไม่มีหมายเลขบรรทัด

คุณสามารถเปลี่ยนได้ด้วย--colorและ-nสวิตช์ (สีและหมายเลขบรรทัดในไฟล์ตามลำดับ)

ในท้ายที่สุดคุณสามารถมีสิ่งต่อไปนี้:

find . -name '*.log' -type f -exec grep --color -n 'pattern' {} '+'

เช่น

$ find . -name '*.c' -type f -exec grep -n 'hello' {} '+' 
./test2/target.c:1:hello

5
ackดีมากและรุ่นที่เร็วกว่าackคือag(เครื่องมือค้นหาซิลเวอร์, geoff.greer.fm/ag )
cfeduke

1
ฉันชอบตัวกรอง-name '*.log'นี้มากกว่าเพราะเร็วกว่า
sdkks

@ cfeduke ฉันไม่ได้ลองส่วนใหญ่เป็นเพราะ ag ไม่ได้เป็นส่วนหนึ่งของที่เก็บ apt เริ่มต้นบน WSL (คุณต้องทำงานกับสิ่งที่คุณมี!)
Pierre-Antoine Guillaume

เคล็ดลับคือการเพิ่ม / dev / null ไปที่ grep เพื่อให้ชื่อไฟล์ปรากฏ
ChuckCottrill

เคล็ดลับคือการค้นหาเฉพาะไดเรกทอรีจากนั้น -exec grep / dev / null {} / * เพื่อรับไฟล์ทั้งหมดด้วย single fork / exec ต่อไดเรกทอรี
ChuckCottrill

12

หากคุณต้องการเรียกเก็บเงินคืนในไดเรกทอรีย่อย:

grep -R 'pattern' .

-Rตัวเลือกที่ไม่ได้เป็นตัวเลือกมาตรฐาน แต่ได้รับการสนับสนุนโดยส่วนใหญ่ที่พบบ่อยgrepการใช้งาน


7
ใช้-rแทน-Rการข้าม symlink เมื่อ grep GNU เกี่ยวข้อง
αғsнιη

1
@AFSHIN ทำไมคุณไม่ต้องการติดตาม symlinks
Kusalananda

4
@ Kusalananda Recursion? แม้ว่าgrepการใช้งานของGNU ในปัจจุบันจะเป็นแบบเรียกซ้ำฉันคิดว่า มิฉะนั้นจะขึ้นอยู่กับความหมายของ "ต้นไม้"
Philippos

2
@Phippippo IMHO การดูแลผู้ใช้ไม่ใช่สิ่งที่เครื่องมือที่grepควรทำ หากผู้ใช้มีการเชื่อมโยงสัญลักษณ์ในโครงสร้างไดเรกทอรีของพวกเขานั่นคือปัญหาของผู้ใช้ :-)
Kusalananda

3
@ Kusalananda และหากระบบให้ลูป? ไม่เคยหลงทาง/sys/devices/cpu/subsystem/devices/cpu/subsystem/devices/cpu/...(-XI เหมือนเครื่องมือดูแลเด็ก ๆ (เว้นแต่พวกเขาจะใช้เวทย์มนตร์แปลก ๆ ที่พวกเขาเรียกว่า "AI") (-;
Philippos

5

ตามที่ระบุไว้ข้างต้น-rหรือ-R(ขึ้นอยู่กับการจัดการ symlink ที่ต้องการ) เป็นตัวเลือกที่รวดเร็ว

อย่างไรก็ตาม-d <action>อาจมีประโยชน์ในบางครั้ง

สิ่งที่ดีเกี่ยวกับ-dคือคำสั่ง skip ซึ่งเงียบ "grep: directory_name: Is a directory" เมื่อคุณเพียงแค่ต้องการสแกนระดับปัจจุบัน

$ grep foo * 
grep: q2: Is a directory 
grep: rt: Is a directory 

$ grep -d skip foo *  
$ 

และแน่นอน:

$ grep -d recurse foo * 
(list of results that don't exist because the word foo isn't in our source code
and I wouldn't publish it anyway).  
$ 

ตัวเลือกที่เป็นประโยชน์จริงๆภายในสคริปต์อื่นดังนั้นคุณจึงไม่ต้อง-d skip 2> /dev/null:)


0

หากคุณจัดการกับไฟล์จำนวนมาก grep จะทำงานเร็วขึ้นหากคุณตัดไฟล์ที่จำเป็นต้องค้นหาลงไปแทนที่จะทำการ grepping ไฟล์ทั้งหมดในโฟลเดอร์ย่อย

ฉันใช้รูปแบบนี้บางครั้ง:

grep "primary" `find . | grep cpp$`

ค้นหาไฟล์ทั้งหมดในโฟลเดอร์ย่อยของ.จุดสิ้นสุดcppนั้น จากนั้น grep ไฟล์เหล่านั้นสำหรับ "หลัก"

หากคุณต้องการคุณสามารถทำการต่อท่อผลลัพธ์เหล่านั้นไปยังการโทร grep เพิ่มเติม:

grep "primary" `find . | grep cpp$` | grep -v "ignoreThis" | grep -i "caseInsensitiveGrep"

1
backtics ไม่ใช่แนวปฏิบัติที่ดีทันสมัยพวกเขาทั้งหมดล้วน แต่ล้าสมัย
Christopher

1
สิ่งนี้จะพังถ้าคุณมีไฟล์ที่มีอักขระพิเศษอยู่ในชื่อ ฉันไม่รู้ว่าพวกเขาจะต้องมีความพิเศษแค่ไหนเพื่อที่จะได้มีความพิเศษเกินกว่าที่มันจะเป็นไปได้ แต่สิ่งที่คุณกำลังทำอยู่นั้นเป็นสิ่งเดียวกับการแยกวิเคราะห์ผลลัพธ์ของ ls ซึ่งก็แย่เช่นกัน
CVn
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.