ฉันจะค้นหารูปแบบหลายบรรทัดในไฟล์ได้อย่างไร


129

ฉันต้องการค้นหาไฟล์ทั้งหมดที่มีรูปแบบสตริงเฉพาะ วิธีแก้ปัญหาแรกที่นึกถึงคือการใช้find piped กับxargs grep :

find . -iname '*.py' | xargs grep -e 'YOUR_PATTERN'

แต่ถ้าฉันต้องการหารูปแบบที่ครอบคลุมมากกว่าหนึ่งบรรทัดฉันก็ติดขัดเพราะ vanilla grep ไม่สามารถหารูปแบบหลายเส้นได้



2
คนนี้แก่กว่าฉันก็บอกว่ามันไม่ซ้ำกัน :)
rogerdpack

@rogerdpack เมื่อทำเครื่องหมายคำถามว่าซ้ำกันอายุของคำถามจะเป็นปัญหาในระดับอุดมศึกษารองจากจำนวนและคุณภาพของคำตอบและคุณภาพของคำถาม
tripleee

คำตอบ:


98

ดังนั้นผมจึงค้นพบpcregrepซึ่งย่อมาจากPerl เข้ากันได้ปกติแสดงออก grep

ตัวอย่างเช่นคุณต้องหาไฟล์ที่ตัวแปร ' _name ' อยู่ในทันทีตามด้วยตัวแปร ' _description ':

find . -iname '*.py' | xargs pcregrep -M '_name.*\n.*_description'

เคล็ดลับ: คุณต้องใส่อักขระแบ่งบรรทัดในรูปแบบของคุณ ขึ้นอยู่กับแพลตฟอร์มของคุณอาจเป็น '\ n', \ r ',' \ r \ n ', ...


7
ดังที่ได้กล่าวไว้โดย halka ด้านล่าง "คุณยังสามารถชักชวน dot wildcard ให้จับคู่ขึ้นบรรทัดใหม่ได้หากคุณเพิ่ม (? s) ในนิพจน์ทั่วไปของคุณ" จากนั้นใช้ grep กับ perl regex โดยเพิ่ม -P หา. -exec grep -nHP '(? s) SELECT. {1,60} จาก. {1,20} table_name' '{}' \;
จิม

8
pcregrepมีให้บริการบนเครื่อง Mac ด้วยbrew install pcre
Jared Beck

1
ได้ดียิ่งขึ้น: ยังใช้งานที่พิมพ์ชื่อไฟล์ก่อนการแข่งขัน:-H pcregrep -HM
Ciro Santilli 郝海东冠状病六四事件法轮功

97

ทำไมคุณไม่ไปหาawk :

awk '/Start pattern/,/End pattern/' filename

2
สิ่งนี้ง่ายต่อการทำความเข้าใจและการใช้งานawkที่มาพร้อมกับระบบ * nix ส่วนใหญ่
Ali Karbassi

24
ดี! มีวิธีที่จะทำให้การจับคู่นี้ไม่โลภหรือไม่?
marcin

3
คุณจะพิมพ์เฉพาะชื่อไฟล์อย่างไรเมื่อมีข้อมูลตรงกัน
bibstha

2
awk '/Start pattern/,/End pattern/ {printf NR " "; print}' filenameคุณสามารถแสดงหมายเลขบรรทัดของการแข่งขันด้วย awk '/Start pattern/,/End pattern/ {printf "%-4s ", NR; print}' filenameคุณสามารถทำให้มันสวยโดยให้หมายเลขบรรทัดที่ความกว้างคงที่:
Robert

ดูเหมือนว่าจะใช้งานได้ดีกับไฟล์เดียวอย่างไรก็ตามถ้าฉันต้องการค้นหาภายในหลายไฟล์ล่ะ
Jinstrong

84

นี่คือตัวอย่างการใช้GNUgrep :

grep -Pzo '_name.*\n.*_description'

-z/ --null-dataปฏิบัติต่อข้อมูลอินพุตและเอาต์พุตเป็นลำดับของบรรทัด

ดูเพิ่มเติมที่นี่


1
ฉันคิดว่านั่นเป็นเพียงอักขระบรรทัดใหม่ตัวเดียวเท่านั้น
Cloud

1
ฉันไม่สามารถใช้ grep สำหรับการค้นหาแบบหลาย-zบรรทัดโดยไม่ใช้แฟล็กจึงไม่แยกการค้นหาในบรรทัดเดียวและ-oพิมพ์เฉพาะส่วนที่ตรงกัน
bbaja42

ฉันพบว่า -o ทำให้มันไม่พิมพ์อะไรเลย แต่ -l ทำงานเพื่อรับรายการไฟล์ (คำสั่งของฉันคือgrep -rzl pattern *-rzo ไม่ทำงาน)
Benubird

5
ฉันแนะนำ '' grep -Pazo '' แทน '' -Pzo '' สำหรับไฟล์ที่ไม่ใช่ ASCII จะดีกว่าเพราะการเปิด -z ไฟล์ที่ไม่ใช่ ASCII อาจทำให้เกิดพฤติกรรม "ข้อมูลไบนารี" ของ grep ซึ่งจะเปลี่ยนค่าที่ส่งคืน สลับ '' -a | --text '' ป้องกันสิ่งนั้น
rloth

ไม่ทำงานบน Mac ที่ติดตั้งคอมไพล์โดยbrew reinstall --with-pcre git
Quanlong

21

grep -Pนอกจากนี้ยังใช้ libpcre แต่มากติดตั้งอย่างกว้างขวางมากขึ้น หากต้องการค้นหาtitleส่วนที่สมบูรณ์ของเอกสาร html แม้ว่าจะมีหลายบรรทัดคุณสามารถใช้สิ่งนี้:

grep -P '(?s)<title>.*</title>' example.html

เนื่องจากโครงการ PCREดำเนินการตามมาตรฐาน perl ให้ใช้เอกสาร perl เพื่ออ้างอิง:


อืมลองตอนนี้แล้วดูเหมือนจะไม่ได้ผล ... gist.github.com/rdp/0286d91624930bd11d0169d6a6337c33
rogerdpack

ฉันไม่รู้ว่าgrepมีตัวเลือกนี้ อาจเป็นเพราะเหตุนี้: นี่เป็นการทดลองขั้นสูงและ grep -P อาจเตือนถึงคุณสมบัติที่ไม่ได้ใช้งาน ; ที่อยู่ภายใต้ CentOS 7 ภายใต้ Fedora 29: นี่เป็นการทดลองและ grep -P อาจเตือนถึงคุณสมบัติที่ไม่ได้ใช้งาน แน่นอนใน BSD grep มันไม่มีเลย คงจะดีถ้ามันไม่ได้ทดลอง แต่มันก็ดีที่ได้รับการเตือนถึงแม้ว่าฉันจะใช้มันเพียงเล็กน้อยก็ตาม
Pryftan

17

นี่คือตัวอย่างที่มีประโยชน์มากขึ้น:

pcregrep -Mi "<title>(.*\n){0,5}</title>" afile.html

ค้นหาแท็กหัวเรื่องในไฟล์ html แม้ว่าจะมีความยาวไม่เกิน 5 บรรทัดก็ตาม

นี่คือตัวอย่างของไม่ จำกัด บรรทัด:

pcregrep -Mi "(?s)<title>.*</title>" example.html 

4
ขอบคุณสำหรับสิ่งนี้. ฉันติดอยู่ที่ไม่รู้ว่าสัญลักษณ์แทนไม่ตรงกับอักขระขึ้นบรรทัดใหม่
แมต

7
@matt: คุณยังสามารถชักชวนดอทไวด์การ์ดให้ตรงกับบรรทัดใหม่ได้หากคุณเพิ่มลง(?s)ในนิพจน์ทั่วไปของคุณเช่น:"(?s)<html>.*</html>"
lubomir.brindza

@matt แน่นอนคุณสามารถตรวจสอบ$(ที่ส่วนท้ายของรูปแบบ) เพื่อแสดงว่าเป็นจุดสิ้นสุดของบรรทัด - แม้ว่านั่นจะไม่ใช่สิ่งเดียวกับการช่วยคุณค้นหารูปแบบเส้นหลาย ๆ glob(7)ดูเพิ่มเติม นอกจากนี้คุณยังอาจพบว่าเว็บไซต์นี้ที่น่าสนใจ: regular-expressions.info
Pryftan


4

คุณสามารถใช้การกรองทางเลือก grep ได้ที่นี่ (ข้อจำกัดความรับผิดชอบ: ฉันเป็นผู้เขียน)

สนับสนุนการจับคู่แบบหลายบรรทัดและ จำกัด การค้นหาเฉพาะไฟล์บางประเภทนอกกรอบ:

ร่อน -m --files '* .py' 'YOUR_PATTERN'

(ค้นหาไฟล์ * .py ทั้งหมดสำหรับรูปแบบ regex หลายบรรทัดที่ระบุ)

สามารถใช้ได้กับระบบปฏิบัติการหลักทั้งหมด ดูหน้าตัวอย่างเพื่อดูว่าสามารถใช้เพื่อแยกค่าหลายบรรทัดจากไฟล์ XML ได้อย่างไร


3

คำตอบนี้อาจเป็นประโยชน์:

Regex (grep) สำหรับการค้นหาหลายบรรทัดที่จำเป็น

หากต้องการค้นหาแบบวนซ้ำคุณสามารถใช้แฟล็ก -R (เรียกซ้ำ) และ - รวม (รูปแบบ GLOB) ดู:

ใช้ grep --exclude / - include syntax เพื่อไม่ให้ grep ผ่านไฟล์บางไฟล์


@ ƉiamondǤeezeƦโปรดทราบว่าการแก้ไขโพสต์ใน LQP ( stackoverflow.com/review/low-quality-posts/19341146 ) จะทำให้การตรวจสอบเป็นโมฆะดังนั้นโปรดแก้ไขหากคุณแน่ใจว่าต้องดูแลโพสต์
fedorqui 'SO หยุดทำร้าย'



1

การใช้ตัวเลือกex / vieditor และglobstar (ไวยากรณ์คล้ายกับawkและsed):

ex +"/string1/,/string3/p" -R -scq! file.txt

aaaจุดเริ่มต้นของคุณอยู่ที่ไหนและbbbเป็นข้อความลงท้ายของคุณ

หากต้องการค้นหาแบบวนซ้ำให้ลอง:

ex +"/aaa/,/bbb/p" -scq! **/*.py

หมายเหตุ: ในการเปิดใช้งาน**ไวยากรณ์ให้เรียกใช้shopt -s globstar(Bash 4 หรือ zsh)

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