วิธี grep ไฟล์หลายพันไฟล์ในไดเรกทอรีสำหรับร้อยสตริงในไฟล์


11

ฉันกำลังพยายามเขียนgrepข้อความและมันกำลังฆ่าฉัน ฉันยังเบื่อที่จะได้รับarguments list too longข้อผิดพลาด subset.txtฉันมีไฟล์ขอเรียกว่า MO43312948มันมีหลายร้อยสายกับสตริงที่เฉพาะเจาะจงเช่น ในไดเรกทอรีวัตถุของฉันฉันมีหลายพันไฟล์และฉันต้องการคัดลอกไฟล์ทั้งหมดที่มีสตริงที่ระบุไว้ในsubset.txtไดเรกทอรีอื่น

ฉันพยายามเริ่มต้นด้วยสิ่งนี้เพียงแค่คืนไฟล์ที่ตรงกันจากไดเรกทอรีวัตถุ

grep -F "$(subset.txt)" /objects/*

ฉันได้รับ `bash: / bin / grep: รายการอาร์กิวเมนต์ยาวเกินไป ''


6
ทำไมคุณ"$(subset.txt)"ถึงออกคำสั่งอย่างนั้น? นั่นคือการทดแทนคำสั่งซึ่งจะทำให้เชลล์ของคุณดำเนินการ subset.txt (ราวกับว่ามันเป็นคำสั่งหรือสคริปต์)
JigglyNaga

คำตอบ:


23

คุณสามารถส่งไดเร็กทอรีเป็นเป้าหมายไปยังgrepด้วย-Rและไฟล์ของรูปแบบอินพุตด้วย-f:

  -f FILE, --file=FILE
          Obtain patterns from FILE, one per line.  If this option is used
          multiple  times  or  is  combined with the -e (--regexp) option,
          search for all patterns given.  The  empty  file  contains  zero
          patterns, and therefore matches nothing.

   -R, --dereference-recursive
          Read all files under each directory,  recursively.   Follow  all
          symbolic links, unlike -r.

ดังนั้นคุณกำลังมองหา:

grep -Ff subset.txt -r objects/

คุณสามารถรับรายการไฟล์ที่ตรงกันด้วย:

grep -Flf subset.txt -r objects/

ดังนั้นหากรายการสุดท้ายของคุณไม่ยาวเกินไปคุณสามารถทำได้:

 mv $(grep -Flf subset.txt -r objects/) new_dir/

หากสิ่งนั้นส่งคืนargument list too longข้อผิดพลาดให้ใช้:

grep -Flf subset.txt -r objects/ | xargs -I{} mv {} bar/

และถ้าชื่อไฟล์ของคุณมีช่องว่างหรือตัวอักษรแปลก ๆ อื่นให้ใช้ (สมมติว่า GNU grep):

grep -FZlf subset.txt -r objects/ | xargs -0I{} mv {} bar/

สุดท้ายหากคุณต้องการยกเว้นไฟล์ไบนารีให้ใช้:

grep -IFZlf subset.txt -r objects/ | xargs -0I{} mv {} bar/

... หรือเพื่อหลีกเลี่ยงการmvเรียกนับพันที่อาจเกิดขึ้นด้วยอาร์กิวเมนต์หนึ่งข้อ: ... | xargs -0 mv -t bar/(สมมติว่าคุณmvสนับสนุน-tตัวเลือก)
David Foerster

11

ใช้

grep -F -f subset.txt 

เพื่อบอก grep ให้อ่านจากsubset.txtไฟล์

คุณอาจใช้การค้นหาเพื่อเดินไฟล์

find . -type f -exec grep -F -f subset.txt {} \;

หรือ

find . -type f -exec grep -F -f subset.txt {}  +

มีข้อได้เปรียบใด ๆ ในการใช้งานfindแทนที่จะเป็นอย่าง-rอื่นนอกจากที่คุณทำการกรองเพิ่มเติม?
2559

1
@phk grep -rค้นหาในsymlink ไปยังไฟล์ปกติซึ่งอาจเป็นที่ต้องการหรือไม่ต้องการ (ถ้ามันชี้ไปที่ต้นไม้เดียวกันคุณกำลังค้นหาไฟล์เดียวกันสองครั้งถ้ามันชี้ไปด้านนอกคุณกำลังค้นหาไฟล์ที่อาจหรือไม่ เป็นที่ต้องการ)
Gilles 'หยุดความชั่วร้าย'

รุ่นที่ทันสมัยgrepมีตัวเลือกในการควบคุมการโต้ตอบกับลิงก์สัญลักษณ์ ( man grepเพื่อกำหนดข้อมูลเฉพาะสำหรับระบบปัจจุบัน) recursive grepจะเป็นจำนวนมากทำงานได้เร็วกว่าที่ไม่ซ้ำกันในทุกไฟล์ผ่านทางgrep find
เพอร์รี

1
@Perry คุณแน่ใจเกี่ยวกับที่? ทำไม? และโปรดทราบว่าคำตอบนี้ใช้ -exec +ดังนั้นมันจะจัดกลุ่มไฟล์และไม่รันหนึ่ง grep ต่อไฟล์
terdon

ฉันยืนแก้ไขฉันไม่รู้ความหมายที่แตกต่างกันของ-exec {} +vs -exec {} \;... คุณเรียนรู้สิ่งใหม่ทุกวัน (ฉันยังคงเห็นเหตุผลว่าทำไม recursive เดียวgrepจะไม่เร็วกว่าการgrepทำงานหลายครั้งจากfindการสร้างกระบวนการและการแยกแบบเหนือศีรษะ แต่ฉัน ไม่มีตัวเลขที่เฉพาะเจาะจงเพื่อส่งสำรอง)
เพอร์รี

3

หากคุณต้องการเพิ่มความเร็วของ grep ให้มากขึ้นคุณสามารถตั้งค่าโลแคลในเชลล์ของคุณก่อนเรียกใช้เช่นใช้ "LC_ALL = c" สิ่งนี้จะได้รับการสืบทอดเป็น grep และจะปิดใช้งานการประมวลผล Unicode เมื่อไม่จำเป็นและในบางกรณีสามารถเพิ่มความเร็วของ grep ได้อย่างมาก บล็อกที่ดีการจัดเก็บเอกสารนี้สามารถพบได้ที่http://www.inmotionhosting.com/support/website/ssh/speed-up-grep-searches-with-lc-all เคล็ดลับนี้ยังสามารถเร่งสคริปเชลล์ bash ได้เช่นกันไม่ใช่แค่ grep

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