ฉันจะ grep ซ้ำผ่านไฟล์. gz ได้อย่างไร


135

ฉันใช้สคริปต์เพื่อดาวน์โหลดข้อความ gmail ของฉันที่บีบอัดไฟล์. eml แบบ raw เป็นไฟล์. gz เป็นประจำ สคริปต์สร้างโฟลเดอร์สำหรับแต่ละวันจากนั้นบีบอัดทุกข้อความเป็นไฟล์ของตัวเอง

ฉันต้องการค้นหาวิธีผ่าน "เก็บถาวร" นี้เพื่อค้นหา

Grep เพียงอย่างเดียวดูเหมือนจะไม่ทำเช่นนั้น ฉันยังลอง SearchMonkey


16
ใช้zgrep:zgrep - search possibly compressed files for a regular expression
Arkadiusz Drabczyk

คำตอบ:


141

หากคุณต้องการ grep ซ้ำในไฟล์. eml.gz ทั้งหมดในไดเรกทอรีปัจจุบันคุณสามารถใช้:

find . -name \*.eml.gz -print0 | xargs -0 zgrep "STRING"

คุณต้องหลบหนีก่อน*เพื่อที่เชลล์จะไม่ตีความมัน -print0บอกให้ find พิมพ์ตัวอักษร null หลังจากพบไฟล์แต่ละไฟล์; xargs -0อ่านจากอินพุตมาตรฐานและรันคำสั่งหลังจากนั้นสำหรับแต่ละไฟล์ zgrepทำงานเหมือนgrepแต่คลายการบีบอัดไฟล์ก่อน


2
'-print0' และ '-0' ไม่บังคับ xargs ใช้ '\ n' โดยค่าเริ่มต้น
Jaime M.

1
พวกเขาจำเป็นถ้าอาจมีอักขระช่องว่างในเส้นทาง ไม่มีเหตุผลอื่นนอกจากความซับซ้อนที่จะไม่ใช้
Daniel Griscom

2
zgrepที่จริงแล้วดูเหมือนจะเร็วกว่าgrepเรียกใช้ไฟล์ที่ไม่มีการบีบอัด ต้องเป็นเพราะไฟล์ที่บีบอัดสามารถอ่านได้จาก HD และแตกไฟล์ได้เร็วกว่าการอ่านไฟล์ที่ไม่บีบอัดจาก HD
Geremia

@JaimeM xargsใช้ช่องว่าง (ช่องว่าง) โดยค่าเริ่มต้น แน่นอนว่าไฟล์แทบจะไม่มีบรรทัดใหม่ในพวกเขา แต่ช่องว่างไม่เคยได้ยินมาก่อน (แม้ว่าประเภท UNIXy ส่วนใหญ่จะขมวดคิ้วอยู่) ที่กล่าวว่าคุณสามารถทำให้ง่ายขึ้นโดยไม่ต้องกังวลเกี่ยวกับช่องว่างได้ง่ายขึ้น: find . -name '*.eml.gz' -exec zgrep "STRING" {} +ที่ได้รับข้อโต้แย้งมากมายต่อการเปิดตัวxargsความปลอดภัยของ-print0/ -0และทั้งหมดโดยไม่ต้องมีค่าใช้จ่ายเพิ่มเติมของการเปิดตัวกระบวนการและท่อและค่อนข้างรัดกุม -execด้วย+มีการระบุ POSIX ดังนั้นจึงควรอยู่ในระบบกึ่งเหมือน UNIX ล่าสุดสำหรับความรู้ของฉัน
ShadowRanger

@Jared มีวิธีที่จะทำการค้นหาสัญลักษณ์ตัวแทนเพียงรู้จุดเริ่มต้นของรูปแบบไฟล์หรือไม่? ตัวอย่างเช่นฉันมีไฟล์. gz ที่มีการประทับวันที่ / เวลาที่ท้ายไฟล์ ABCLog04_18_18_2_21.gz มีวิธีในการค้นหาไฟล์ที่เริ่มต้นด้วย ABC * ซ้ำ ๆ หรือไม่ ฉันพยายามแทนที่\*.eml.gzในตัวอย่างของคุณด้านบนด้วยABCLog*และได้รับข้อผิดพลาดเกี่ยวกับรูปแบบไฟล์:find: paths must precede expression: ABCLog-2018-03-12-10-16-1.log.gz Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]
DevelopingDeveloper

68

zgrepมีจำนวนมากของความสับสนที่นี่เป็นเพราะมีไม่ได้เป็นเพียงหนึ่ง ฉันมีสองรุ่นในระบบของฉันzgrepจากgzipและจากzgrep อดีตเป็นเพียงสคริปต์เสื้อคลุมที่เรียกร้องzutils gzip -cdfqไม่รองรับ-r, --recursiveสวิตช์ 1
หลังเป็นc++โปรแกรมและสนับสนุน-r, --recursiveตัวเลือก
การทำงานzgrep --version | head -n 1จะเปิดเผยว่าหนึ่ง (ถ้ามี) ของพวกเขาคือค่าเริ่มต้น:

zgrep (gzip) 1.6

เป็นสคริปต์ wrapper

zgrep (zutils) 1.3

เป็นcppปฏิบัติการ
หากคุณมีหลังคุณสามารถเรียกใช้:

zgrep 'pattern' -r --format=gz /path/to/dir

อย่างไรก็ตามตามที่แนะนำfind+ zgrepจะทำงานได้ดีเท่า ๆ กันกับเวอร์ชันใดเวอร์ชันหนึ่งzgrep:

find /path/to/dir -name '*.gz' -exec zgrep -- 'pattern' {} +

หากzgrepระบบของคุณหายไป (ไม่น่าเป็นไปได้สูง) คุณสามารถลองใช้:

find /path/to/dir -name '*.gz' -exec sh -c 'gzip -cd "$0" | grep -- "pattern"' {} \;

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


1: เพราะมันจะเป็นปัญหา


1
ถ้าzgrepจาก zutils sudo apt-get install zutilsไม่สามารถใช้ได้คุณสามารถติดตั้งในอูบุนตูกับ
therealmarv

1
ดำเนินการต่อจาก @therealmarv ... จากนั้น Ubuntu จะใช้ zutils zgrep แทน gzip one ถ้างั้นก็ใช้งานได้!
Elijah Lynn

มีวิธีพิมพ์หมายเลขบรรทัดของไฟล์ที่รูปแบบตรงกันหรือไม่?
DogEatDog

@DogEatDog - เช่นเดียวgrep -n, zgrep -nจะพิมพ์ no.s. บรรทัด มันอยู่ในคู่มือ ...
don_crissti

7

agเป็นรุ่นที่ grepมีคุณสมบัติพิเศษบางอย่างที่ดี

  • มีตัวเลือก -z สำหรับไฟล์บีบอัด
  • มีคุณสมบัติ ack หลายอย่าง
  • มันเร็ว

ดังนั้น:

ag -r -z your-pattern-goes-here   folder

หากไม่ได้ติดตั้ง

apt-get install silversearcher-ag   (debian and friends)
yum install the_silver_searcher     (fedora)
brew install the_silver_searcher    (mac)

1
ฉันได้รับag: truncated file: Successเป็นผล ฉันควรเพิ่มการตั้งค่าสถานะอื่นใดอีกหรือไม่
Yar

4

การเรียกซ้ำเพียงอย่างเดียวนั้นง่าย:

   -r, --recursive
          Read all files  under  each  directory,  recursively,  following
          symbolic  links  only  if they are on the command line.  This is
          equivalent to the -d recurse option.

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

อย่างไรก็ตามสำหรับไฟล์บีบอัดที่คุณต้องการ:

shopt globstar 
for file in /path/to/directory/**/*gz; do zcat ""$file" | grep pattern; done

path/to/directory ควรเป็นไดเรกทอรีหลักที่มีไดเรกทอรีย่อยสำหรับแต่ละวัน


zgrepเป็นคำตอบที่ชัดเจน แต่น่าเสียดายที่มันไม่สนับสนุนการ-rตั้งค่าสถานะ จากman zgrep:

ตัวเลือก grep เหล่านี้จะทำให้ zgrep ยกเลิกด้วยรหัสข้อผิดพลาด: (- [d rR zZ ] | --di * | --exc * | --inc * | --rec * | --nu *)


3

หากระบบของคุณมี zgrep คุณก็สามารถทำได้

zgrep -irs your-pattern-goes-here the-folder-to-search-goes-here/

หากระบบของคุณไม่มี zgrep คุณสามารถใช้คำสั่งfindเพื่อรัน zcat และ grep สำหรับแต่ละไฟล์ดังนี้:

find the-folder-to-search-goes-here/ -name '*.gz' \ -exec sh -c 'echo "Searching {}" ; zcat "{}" | grep your-pattern-goes-here ' \;


ให้อภัยฉันด้วยความเป็นมิตรกับสิ่งแวดล้อมในสิ่งนี้ ... ไฟล์ที่จะค้นหาผ่านเป็นเลเยอร์สองชั้นที่ลึก ~ / gmvault-db / db / 2015-02 มีโฟลเดอร์สำหรับแต่ละเดือนที่เก็บถาวรจากนั้นภายใต้ไฟล์. gz สำหรับเดือนนั้นจะถูกเก็บไว้ ถ้าฉันค้นหา. mil ในทรีทั้งหมดนั่นคือสิ่งที่ฉันจะทำอย่างไร หา ~ / gmvault-db / db / -name '* .gz' \ -exec sh -c 'echo "กำลังค้นหา {}"; zcat "{}" | grep .mil '\;
Kendor

1
ไม่เป็นไร - "r" ใน -ir จะทำให้ zgrep ค้นหาซ้ำ คำสั่ง find ทำงานโดยวนซ้ำดังนั้นไฟล์ใด ๆ ที่ลงท้ายด้วย. gz จะถูก zcatted และส่งผ่านไปยัง grep (และ {} จะถูกขยายไปยังเส้นทางสัมพัทธ์ของไฟล์ที่กำลังจะถูกค้นหา) ดังนั้นเมื่อคุณได้รับผลกระทบมันจะถูกนำหน้าด้วย Searching ~/gmvault-db/db/2015-02/03/whatever.gz
เนทจาก Kalamazoo

นี่คือสิ่งที่ฉันได้รับกลับมา: ค้นหา: "พา ธ ต้องนำหน้านิพจน์: -exec" นี่คือคำสั่งที่ฉันใช้: find ~ / gmvault-db / db / -name '* .gz' \ -exec sh -c 'echo "การค้นหา { } "; zcat "{}" | grep .mil '\;
Kendor

นำแบ็กสแลชออกระหว่าง '* .gz' และ -exec
Nate จาก Kalamazoo

4
zgrepจะไม่รับ-rธงด้วยเหตุผลบางอย่าง ที่กล่าวถึงในman zgrep(ดูคำตอบของฉัน)
terdon

0

xzgrep -l "string" ./*/*.eml.gz

xzgrep เป็นอนุพันธ์ของ zgrep utils (less / bin / xzgrep)

จากหน้า Man:

xzgrep เรียกใช้ grep (1) ในไฟล์ซึ่งอาจไม่บีบอัดหรือบีบอัดด้วย xz (1), lzma (1), gzip (1), bzip2 (1), หรือ lzop (1) ตัวเลือกทั้งหมดที่ระบุจะถูกส่งโดยตรงไปยัง grep (1)

-l พิมพ์ชื่อไฟล์ที่ตรงกัน

-R สำหรับการเรียกซ้ำจะไม่ทำงานตามที่กำหนดไว้เป็นพิเศษในสคริปต์ แต่เปลือกที่เรียบง่ายนั้นควรอยู่กับเรา

./*/*.eml.gz

จากเส้นทางสัมพัทธ์ที่. /today/sample.eml.gz จับคู่กับอินสแตนซ์ทั้งหมดที่อยู่ต่ำกว่าตำแหน่งสัมพัทธ์ของเราหนึ่งระดับในเชลล์ซึ่งลงท้ายด้วย ".eml.gz"

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