grep ในสองสามพันไฟล์


13

ฉันมีไดเรกทอรีที่มี cca 26,000 ไฟล์และฉันต้องการ grep ในไฟล์เหล่านี้ทั้งหมด ปัญหาคือฉันต้องการให้เร็วที่สุดดังนั้นจึงไม่เหมาะที่จะสร้างสคริปต์โดยที่ grep จะใช้ชื่อของไฟล์เดียวจากคำสั่ง find และเขียนรายการที่ตรงกันลงในไฟล์ ก่อนที่ปัญหา "รายการอาร์กิวเมนต์ยาวเกินไป" ต้องใช้เวลาประมาณ 2 นาทีในการ grep ในไฟล์นี้ทั้งหมด ความคิดใด ๆ ที่จะทำอย่างไร แก้ไข: มีสคริปต์ที่สร้างไฟล์ใหม่ตลอดเวลาดังนั้นจึงเป็นไปไม่ได้ที่จะนำไฟล์ทั้งหมดไปยังไฟล์ dirs ที่แตกต่างกัน


1
ใช้findกับxargsหรือgrep -R
Eddy_Em

ใช้งานได้ดี แต่ใช้เวลา 10 นาที ...
user2778979

คำตอบ:


19

ด้วยfind:

cd /the/dir
find . -type f -exec grep pattern {} +

( -type fเป็นการค้นหาในไฟล์ปกติเท่านั้น(ยกเว้นการเชื่อมโยงด้วยแม้ว่าจะชี้ไปที่ไฟล์ปกติ) หากคุณต้องการค้นหาไฟล์ทุกประเภทยกเว้นไดเรกทอรี (แต่ระวังว่ามีไฟล์บางประเภทเช่น fifos หรือ / dev / ศูนย์ที่ โดยทั่วไปคุณไม่ต้องการอ่าน) แทนที่-type fด้วย GNU เฉพาะ! -xtype d( -xtype dจับคู่สำหรับไฟล์ของไดเรกทอรีประเภทหลังจากความละเอียด symlink))

ด้วย GNU grep:

grep -r pattern /the/dir

(แต่ระวังว่าถ้าคุณไม่มี grep GNU รุ่นล่าสุดที่จะติดตาม symlink เมื่อเรียงลำดับจากไดเรกทอรี) ไฟล์ที่ไม่ปกติจะไม่ถูกค้นหาจนกว่าคุณจะเพิ่ม-D readตัวเลือก GNU รุ่นล่าสุดgrepจะยังไม่ค้นหาการเชื่อมโยงภายใน

GNU รุ่นเก่ามากfindไม่รองรับ{} +ไวยากรณ์มาตรฐานแต่คุณสามารถใช้ที่ไม่ได้มาตรฐานได้:

cd /the/dir &&
  find . -type f -print0 | xargs -r0 grep pattern

การแสดงมีแนวโน้มว่าจะถูกผูกไว้ I / O นั่นคือเวลาที่จะทำการค้นหาจะเป็นเวลาที่จำเป็นในการอ่านข้อมูลทั้งหมดจากที่เก็บข้อมูล

หากข้อมูลอยู่ในดิสก์อาร์เรย์ที่ซ้ำซ้อนการอ่านไฟล์หลายไฟล์ในแต่ละครั้งอาจช่วยเพิ่มประสิทธิภาพ (และอาจทำให้ไฟล์เหล่านั้นด้อยลง) หากการแสดงไม่ได้ผูก I / O (เพราะเช่นข้อมูลทั้งหมดอยู่ในแคช) และคุณมี CPU หลายตัวการทำงานพร้อมกันgrepsอาจช่วยได้เช่นกัน คุณสามารถทำได้ด้วยตัวเลือกxargsของGNU-P

ตัวอย่างเช่นหากข้อมูลอยู่ในอาเรย์ RAID1 ที่มี 3 ไดรฟ์หรือหากข้อมูลอยู่ในแคชและคุณมีซีพียู 3 ตัวที่มีเวลาว่าง:

cd /the/dir &&
  find . -type f -print0 | xargs -n1000 -r0P3 grep pattern

(ที่นี่ใช้-n1000เพื่อวางไข่ใหม่grepทุกๆ 1,000 ไฟล์สูงสุด 3 ทำงานพร้อมกันในแต่ละครั้ง)

อย่างไรก็ตามโปรดทราบว่าหากผลลัพธ์ของการgrepเปลี่ยนเส้นทางคุณจะจบลงด้วยการส่งออก interleaved ไม่ดีจาก 3 grepกระบวนการซึ่งในกรณีนี้คุณอาจต้องการที่จะเรียกใช้เป็น:

find . -type f -print0 | stdbuf -oL xargs -n1000 -r0P3 grep pattern

(สถานที่ล่าสุดของกนูหรือระบบ FreeBSD) หรือใช้--line-bufferedตัวเลือกของ grepGNU

ถ้าpatternเป็นสตริงคงที่การเพิ่ม-Fตัวเลือกสามารถปรับปรุงเรื่องต่างๆได้

หากไม่ใช่ข้อมูลอักขระหลายไบต์หรือสำหรับรูปแบบที่ตรงกันนั้นไม่สำคัญว่าข้อมูลนั้นเป็นอักขระหลายไบต์หรือไม่ก็ตาม:

cd /the/dir &&
  LC_ALL=C grep -r pattern .

สามารถปรับปรุงประสิทธิภาพได้อย่างมาก

หากคุณทำการค้นหาดังกล่าวบ่อยครั้งคุณอาจต้องการจัดทำดัชนีข้อมูลโดยใช้หนึ่งในเครื่องมือค้นหามากมาย


3

26,000 ไฟล์ในไดเรกทอรีเดียวนั้นมีประโยชน์มากมายสำหรับระบบไฟล์ส่วนใหญ่ เป็นไปได้ว่าส่วนสำคัญของการอ่านไดเรกทอรีขนาดใหญ่นี้ พิจารณาแยกมันเป็นไดเรกทอรีขนาดเล็กโดยมีเพียงไม่กี่ร้อยไฟล์ต่อไฟล์

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


ขอบคุณฉันจะ google เกี่ยวกับเรื่องนี้และฉันจะแยกมันออก ฉันทำสิ่งที่คุณกำลังเขียนและใช้เวลานานกว่า grep เพียง 3 เท่า ...
user2778979

Gilles คุณกำลังบอกว่าประสิทธิภาพจะแตกต่างกันอย่างมากสำหรับไฟล์ 26,000 ไฟล์ในหนึ่งไดเรกทอรีเทียบกับ 26,000 ไฟล์ที่กระจายอยู่พูดกัน 100 ไดเรกทอรีหรือไม่
user001

1
@ user001 ใช่ ความแตกต่างนั้นขึ้นอยู่กับระบบไฟล์และอาจเป็นที่เก็บข้อมูลพื้นฐาน แต่ฉันคาดหวังว่าระบบไฟล์ใด ๆ ที่จะวัดได้เร็วขึ้นด้วย 260 ไฟล์ในแต่ละ 100 ไดเรกทอรีเทียบกับ 26000 ไฟล์ในไดเรกทอรีเดียว
Gilles 'SO- หยุดความชั่วร้าย'

ขอขอบคุณสำหรับการชี้แจง. ฉันถามติดตามคำถามในประเด็นนี้เพื่อให้เข้าใจพื้นฐานสำหรับความแตกต่างที่
user001

0

หากคุณต้องการ grep ไฟล์ทั้งหมดหลาย ๆ ครั้ง (ตามที่คุณพูด, เรียกใช้สคริปต์) ฉันขอแนะนำให้ดูที่ ram disk, คัดลอกไฟล์ทั้งหมดที่นั่นและจากนั้น grep ไฟล์หลาย ๆ ครั้ง, สิ่งนี้จะช่วยเร่งการค้นหาของคุณ อย่างน้อย 100x

คุณต้องการหน่วยความจำเพียงพอ มิฉะนั้นคุณควรตรวจสอบการจัดทำดัชนีไฟล์เช่น ลงใน lucene หรือฐานข้อมูล nosql จากนั้นเรียกใช้แบบสอบถามตามนั้น


ดังที่ระบุไว้ที่อื่นสิ่งนี้ไม่ได้ช่วยให้มีไฟล์มากเกินกว่าที่จะเรียกgrepใช้ได้ นอกจากนี้ยังมีจุดที่: "มีสคริปต์ที่สร้างไฟล์ใหม่ตลอดเวลาดังนั้นจึงเป็นไปไม่ได้ที่จะนำไฟล์ทั้งหมดไปยัง dirs ที่แตกต่างกัน"
Jeff Schaller

-2

ไฟล์ทั้งหมดในไดเรกทอรี

grep 'search string' *

กับแบบเรียกซ้ำ

grep -R 'search string' *

สนใจที่จะอธิบาย -1 หรือไม่?
Markus

4
ฉันไม่ได้ลงคะแนน แต่มีปัญหาบางอย่างกับคุณ: OP กล่าวถึง "รายการ arg ยาวเกินไป" ซึ่งคนแรกของคุณจะไม่แก้ไขและน่าจะเป็นสิ่งที่ OP ทำมาก่อน อันที่สองไม่ได้ช่วยอะไรในเรื่องนั้น (จะช่วยให้คุณใช้.แทน*) *จะยกเว้นไฟล์จุด (แม้ว่าจะมี -R ไม่ใช่ไฟล์ในไดเรกทอรีที่เรียกซ้ำ) -R ซึ่งตรงข้ามกับ -r จะติดตาม symlink แม้ใน grep GNU รุ่นล่าสุด นอกจากนี้คุณยังจะมีปัญหากับไฟล์ในไดเรกทอรีปัจจุบันที่ชื่อขึ้นต้นด้วย-
Stéphane Chazelas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.