ฉันจะส่งรายการไฟล์ไปยัง grep ได้อย่างไร


98

ฉันกำลังใช้งานfindและรับรายการไฟล์ที่ฉันต้องการgrepผ่าน ฉันจะไพพ์รายชื่อนั้นได้grepอย่างไร?

คำตอบ:


116

กรณีทั่วไปที่ทำงานกับคำสั่งใด ๆ ที่เขียนไปยัง stdout คือการใช้xargsซึ่งจะช่วยให้คุณแนบอาร์กิวเมนต์บรรทัดคำสั่งจำนวนเท่าใดก็ได้ที่ส่วนท้ายของคำสั่ง:

$ find … | xargs grep 'search'

หรือเพื่อฝังคำสั่งในgrepบรรทัดของคุณด้วย backticks หรือ$()ซึ่งจะรันคำสั่งและแทนที่ผลลัพธ์:

$ grep 'search' $(find …)

โปรดทราบว่าคำสั่งเหล่านี้จะไม่ทำงานหากชื่อไฟล์มีช่องว่างหรือ“ อักขระแปลก ๆ ” อื่น ๆ ( \'"สำหรับ xargs \[*?สำหรับ$(find …))


อย่างไรก็ตามในกรณีเฉพาะของfindความสามารถในการเรียกใช้โปรแกรมบนอาร์กิวเมนต์ที่กำหนดนั้นมีอยู่แล้วภายใน:

$ find … -exec grep 'search' {} \;

ทุกสิ่งระหว่าง-execและ;เป็นคำสั่งให้ดำเนินการ; จะถูกแทนที่ด้วยชื่อไฟล์ที่พบโดย{} findที่จะดำเนินการแยกต่างหากgrepสำหรับแต่ละไฟล์ เนื่องจากgrepสามารถใช้ชื่อไฟล์จำนวนมากและค้นหาพวกเขาทั้งหมดคุณสามารถเปลี่ยน;เพื่อ+ที่จะบอกหาที่จะผ่านทั้งหมดชื่อไฟล์ที่ตรงกันไปgrepในครั้งเดียว:

$ find … -exec grep 'search' {} \+

1
ควรสังเกตว่าสองรูปแบบแรกไม่ทำงานกับชื่อไฟล์ที่มีช่องว่าง
enzotib

1
find ... -type f -print0 | xargs -r0 grep 'search' /dev/nullฉันชอบ QED ในขณะที่-exec +มีประสิทธิภาพมากมันไม่ได้มีอยู่ในทุกรุ่นของการค้นหา
Arcege

น่าเศร้าที่ฉันไม่สามารถตรวจสอบคุณถูกต้อง 3 ครั้ง
Arcabard

3
ผมขอแนะนำให้ใช้มากกว่ากว่า-exec xargsถ้าคุณใช้-execin find, มันจะสร้างเชลล์เพียงอันเดียวเพื่อgrepสำหรับเนื้อหา ถ้าคุณใช้xargsก็จะสร้างเปลือกหอยสอง: หนึ่งสำหรับfindและอื่น ๆ xargsสำหรับ

2
โดยการทดสอบผมพบว่า$ find … -exec grep 'search' {} \+รูปแบบเป็นมากเร็วที่สุด
gogoud

9

บางรุ่นของgrep(เช่นบน Linux หรือBSDหรือ Mac OS X ที่ไม่ได้ฝังตัว) มี-rตัวเลือกเพื่อทำการค้นหาแบบเรียกซ้ำ บน OpenBSD ใช้-R(และไม่มี--excludeตามตัวอย่างด้านล่าง) นี้ครอบคลุมถึงชุดที่เรียบง่ายของด้วยfindgrep

หากการดำเนินการของคุณไม่ได้มี-Rธงหรือถ้าคุณต้องการเกณฑ์ไฟล์จับคู่นักเล่น, คุณสามารถใช้-execหลักของการที่จะทำให้มันรันfind grepการfindใช้งานรุ่นเก่าบางอย่างไม่สนับสนุน-exec... +; ในระบบเหล่านี้ใช้;แทน+(จะเรียกgrepหนึ่งครั้งต่อไฟล์ดังนั้นมันจะช้าลง แต่ไม่เช่นนั้นผลลัพธ์จะเหมือนกัน) สังเกต/dev/nullเคล็ดลับที่จะทำให้grepชื่อไฟล์แม้ว่ามันจะเกิดขึ้นกับไฟล์เดียว (GNU grep และ FreeBSD / NetBSD / OSX grep มี-Hตัวเลือกเพื่อให้ได้ผลเหมือนกัน)

find . -type f -name '*.o' -prune -o -exec grep 'needle' /dev/null {} +
grep -r --exclude='*.o' 'needle' .

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