จะหารูปแบบข้ามหลายบรรทัดโดยใช้ grep ได้อย่างไร


208

ฉันต้องการค้นหาไฟล์ที่มี "abc" และ "efg" ตามลำดับและทั้งสองสตริงนั้นอยู่ในบรรทัดที่ต่างกันในไฟล์นั้น เช่นไฟล์ที่มีเนื้อหา:

blah blah..
blah blah..
blah abc blah
blah blah..
blah blah..
blah blah..
blah efg blah blah
blah blah..
blah blah..

ควรจับคู่


คำตอบ:


225

Grep ไม่เพียงพอสำหรับการดำเนินการนี้

pcregrepซึ่งพบในระบบ Linux ส่วนใหญ่สามารถใช้เป็น

pcregrep -M  'abc.*(\n|.)*efg' test.txt

ที่-M, --multiline ช่วยให้รูปแบบเพื่อให้ตรงกับมากกว่าหนึ่งบรรทัด

มีpcre2grep ที่ใหม่กว่าด้วย ทั้งสองจะให้บริการโดยโครงการ PCRE

pcre2grep สามารถใช้ได้สำหรับ Mac OS X ผ่านMac Portsเป็นส่วนหนึ่งของพอร์ตpcre2:

% sudo port install pcre2 

และผ่านHomebrewเป็น:

% brew install pcre

หรือสำหรับ pcre2

% brew install pcre2

pcre2grep ยังมีอยู่บน Linux (Ubuntu 18.04+)

$ sudo apt install pcre2-utils # PCRE2
$ sudo apt install pcregrep    # Older PCRE

11
@StevenLu -M, --multiline- อนุญาตให้รูปแบบจับคู่มากกว่าหนึ่งบรรทัด
ผู้ถือแหวน

7
โปรดทราบว่า. * (\ n |.) * เทียบเท่ากับ (\ n |.) * และหลังสั้นกว่า ยิ่งกว่านั้นในระบบของฉัน "pcre_exec () error -8" เกิดขึ้นเมื่อฉันเรียกใช้เวอร์ชันที่ยาวกว่า ดังนั้นลอง 'abc (\ n |.) * efg' แทน!
daveagp

6
คุณต้องทำให้การแสดงออกที่ไม่ใช่โลภในกรณีตัวอย่าง:'abc.*(\n|.)*?efg'
ผู้ถือแหวน

4
และคุณสามารถละเว้นตัวแรก.*-> 'abc(\n|.)*?efg'เพื่อให้ regex สั้นลง (และจะอวดความรู้)
Michi

6
pcregrepจะทำให้สิ่งต่าง ๆ ง่ายขึ้น แต่grepก็ใช้ได้เช่นกัน ตัวอย่างเช่นดูstackoverflow.com/a/7167115/123695
Michael Mior

113

ฉันไม่แน่ใจว่าเป็นไปได้ด้วย grep หรือไม่ แต่ sed ทำให้มันง่ายมาก:

sed -e '/abc/,/efg/!d' [file-with-content]

4
ไม่พบไฟล์มันส่งคืนส่วนที่ตรงกันจากไฟล์เดียว
shiggity

11
@Lj ได้โปรดอธิบายคำสั่งนี้ได้ไหม ฉันคุ้นเคยกับsedแต่ถ้าไม่เคยเห็นการแสดงออกเช่นนี้มาก่อน
Anthony

1
@ แอนโทนี่มีการบันทึกไว้ใน man page ของ sed ภายใต้ที่อยู่ สิ่งสำคัญคือต้องตระหนักว่า / abc / & / efg / เป็นที่อยู่
Squidly

49
ฉันสงสัยว่าคำตอบนี้จะเป็นประโยชน์หากมีคำอธิบายเพิ่มเติมเล็กน้อยและในกรณีนี้ฉันจะได้รับการโหวตอีกครั้ง ฉันรู้บิตของ sed แต่ไม่เพียงพอที่จะใช้คำตอบนี้เพื่อสร้างรหัสทางออกที่มีความหมายหลังจากครึ่งชั่วโมงของการเล่นซอ เคล็ดลับ: 'RTFM' ไม่ค่อยได้คะแนนมากใน StackOverflow เนื่องจากความคิดเห็นก่อนหน้านี้ของคุณแสดงขึ้น
Michael Scheper

25
คำอธิบายอย่างรวดเร็วจากตัวอย่าง: sed '1,5d': ลบบรรทัดระหว่าง 1 และ 5 sed '1,5! d': ลบบรรทัดที่ไม่อยู่ระหว่าง 1 ถึง 5 (เช่นเก็บบรรทัดไว้) จากนั้นแทนจำนวนคุณสามารถ ค้นหาบรรทัดด้วย / pattern /. ดูเพิ่มเติมที่ง่ายกว่าด้านล่าง: sed -n '/ abc /, / efg / p' p สำหรับพิมพ์และแฟ
ล็ก

86

นี่คือทางออกที่ได้รับแรงบันดาลใจจากคำตอบนี้ :

  • หาก 'abc' และ 'efg' สามารถอยู่ในบรรทัดเดียวกัน:

    grep -zl 'abc.*efg' <your list of files>
  • หาก 'abc' และ 'efg' ต้องอยู่ในบรรทัดที่ต่างกัน:

    grep -Pzl '(?s)abc.*\n.*efg' <your list of files>

params:

  • -zถืออินพุตเป็นชุดของบรรทัดแต่ละบรรทัดถูกยกเลิกด้วยศูนย์ไบต์แทนการขึ้นบรรทัดใหม่ เช่น grep ถือว่าอินพุตเป็นหนึ่งบรรทัดใหญ่

  • -l ชื่อพิมพ์ของไฟล์อินพุตแต่ละไฟล์ซึ่งปกติแล้วเอาต์พุตจะถูกพิมพ์

  • (?s)เปิดใช้งาน PCRE_DOTALL ซึ่งหมายความว่า '.' ค้นหาตัวละครหรือขึ้นบรรทัดใหม่


@syntaxerror lไม่มีผมคิดว่ามันเป็นเพียงกรณีที่ต่ำกว่า AFAIK ไม่มี-1ตัวเลือกตัวเลข
Sparhawk

ดูเหมือนว่าคุณถูกต้องบางทีฉันอาจพิมพ์ผิดเมื่อทำการทดสอบ ไม่ว่าในกรณีใด ๆ ขออภัยในการวางหลักฐานเท็จ
ไวยากรณ์

6
มันยอดเยี่ยมมาก ฉันมีคำถามหนึ่งข้อเกี่ยวกับเรื่องนี้ หาก-zตัวเลือกระบุ grep เพื่อรักษาบรรทัดใหม่zero byte charactersแล้วทำไมเราต้อง(?s)ใช้ regex? หากเป็นอักขระที่ไม่ใช่บรรทัดใหม่แล้วไม่ควร.จับคู่อักขระนั้นโดยตรงหรือไม่
Durga Swaroop

1
-z (aka --null-data) และ (? s) เป็นสิ่งที่คุณต้องการเพื่อจับคู่หลายบรรทัดกับ grep มาตรฐาน ผู้ใช้บน MacOS โปรดแสดงความคิดเห็นเกี่ยวกับความพร้อมใช้งานของตัวเลือก -z หรือ --null-data ในระบบของคุณ!
Zeke Fast

4
-z ไม่สามารถใช้งานบน MacOS ได้แน่นอน
Dylan Nicholson

33

sed ควรเพียงพอตามที่โปสเตอร์ LJ ระบุไว้ข้างต้น

แทน! d คุณสามารถใช้ p เพื่อพิมพ์:

sed -n '/abc/,/efg/p' file

16

ฉันวางใจอย่างมากกับ pcregrep แต่ด้วย grep ที่ใหม่กว่าคุณไม่จำเป็นต้องติดตั้ง pcregrep สำหรับคุณสมบัติมากมาย grep -Pใช้เพียงแค่

ในตัวอย่างของคำถามของ OP ฉันคิดว่าตัวเลือกต่อไปนี้ทำงานได้ดีโดยการจับคู่ที่ดีที่สุดที่สองฉันเข้าใจคำถาม:

grep -Pzo "abc(.|\n)*efg" /tmp/tes*
grep -Pzl "abc(.|\n)*efg" /tmp/tes*

ฉันคัดลอกข้อความเป็น / tmp / test1 และลบ 'g' และบันทึกเป็น / tmp / test2 นี่คือผลลัพธ์ที่แสดงว่ารายการแรกแสดงสตริงที่ตรงกันและรายการที่สองแสดงเฉพาะชื่อไฟล์ (ทั่วไป -o คือแสดงการจับคู่และทั่วไป -l คือแสดงเฉพาะชื่อไฟล์) โปรดทราบว่า 'z' เป็นสิ่งจำเป็นสำหรับ multiline และ '(. | \ n)' หมายถึงการจับคู่ 'สิ่งอื่นที่ไม่ใช่ newline' หรือ 'newline' - เช่นอะไร:

user@host:~$ grep -Pzo "abc(.|\n)*efg" /tmp/tes*
/tmp/test1:abc blah
blah blah..
blah blah..
blah blah..
blah efg
user@host:~$ grep -Pzl "abc(.|\n)*efg" /tmp/tes*
/tmp/test1

หากต้องการตรวจสอบว่ารุ่นของคุณใหม่เพียงพอหรือไม่ให้เรียกใช้man grepและดูว่ามีบางอย่างที่คล้ายกันนี้ปรากฏขึ้นที่ด้านบนหรือไม่:

   -P, --perl-regexp
          Interpret  PATTERN  as a Perl regular expression (PCRE, see
          below).  This is highly experimental and grep -P may warn of
          unimplemented features.

นั่นคือจาก GNU grep 2.10


14

สิ่งนี้สามารถทำได้อย่างง่ายดายโดยใช้ครั้งแรกtrเพื่อแทนที่บรรทัดใหม่ด้วยอักขระอื่น:

tr '\n' '\a' | grep -o 'abc.*def' | tr '\a' '\n'

ที่นี่ฉันกำลังใช้อักขระสัญญาณเตือน\a(ASCII 7) แทนที่บรรทัดใหม่ นี้เกือบจะไม่เคยพบในข้อความของคุณและgrepสามารถจับคู่กับหรือตรงกับมันโดยเฉพาะกับ.\a


1
นี่เป็นวิธีการของฉัน แต่ฉันใช้\0และจำเป็นgrep -aและจับคู่กับ\x00... คุณช่วยให้ฉันง่ายขึ้น! echo $log | tr '\n' '\0' | grep -aoE "Error: .*?\x00Installing .*? has failed\!" | tr '\0' '\n'ได้ตอนนี้echo $log | tr '\n' '\a' | grep -oE "Error: .*?\aInstalling .*? has failed\!" | tr '\a' '\n'
Charlie Gorichanaz

1
grep -oใช้
kyb

7

awk หนึ่งซับ:

awk '/abc/,/efg/' [file-with-content]

4
สิ่งนี้จะพิมพ์จากabcถึงถึงจุดสิ้นสุดอย่างมีความสุขหากรูปแบบจุดสิ้นสุดไม่ปรากฏในไฟล์หรือรูปแบบจุดสิ้นสุดสุดท้ายหายไป คุณสามารถแก้ไขได้ แต่สคริปต์จะค่อนข้างซับซ้อน
tripleee

วิธีแยก/efg/ออกจากเอาต์พุตได้อย่างไร
kyb

6

คุณสามารถทำได้อย่างง่ายดายถ้าคุณสามารถใช้ Perl

perl -ne 'if (/abc/) { $abc = 1; next }; print "Found in $ARGV\n" if ($abc && /efg/); }' yourfilename.txt

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

perl -e '@lines = <>; $content = join("", @lines); print "Found in $ARGV\n" if ($content =~ /abc.*efg/s);' yourfilename.txt

พบว่าคำตอบที่สองมีประโยชน์ในการแยกบล็อกหลายบรรทัดทั้งหมดด้วยการจับคู่ในสองบรรทัด - ต้องใช้การจับคู่ที่ไม่ใช่โลภ ( .*?) เพื่อให้ได้คู่ที่น้อยที่สุด
RichVel

5

ฉันไม่รู้ว่าฉันจะทำอย่างไรกับ grep แต่ฉันจะทำสิ่งนี้กับ awk:

awk '/abc/{ln1=NR} /efg/{ln2=NR} END{if(ln1 && ln2 && ln1 < ln2){print "found"}else{print "not found"}}' foo

คุณต้องระวังว่าคุณจะทำสิ่งนี้อย่างไร คุณต้องการให้ regex จับคู่สตริงย่อยหรือทั้งคำหรือไม่? เพิ่มแท็ก \ w ตามความเหมาะสม นอกจากนี้แม้ว่าสิ่งนี้จะสอดคล้องกับวิธีการที่คุณระบุตัวอย่าง แต่ก็ไม่ได้ผลเมื่อ abc ปรากฏเป็นครั้งที่สองหลังจาก efg หากคุณต้องการจัดการสิ่งนั้นให้เพิ่มคำว่า if ตามความเหมาะสมใน / abc / case เป็นต้น


3

น่าเศร้าที่คุณทำไม่ได้ จากgrepเอกสาร:

grep ค้นหาไฟล์อินพุตที่มีชื่อ (หรืออินพุตมาตรฐานหากไม่มีไฟล์ชื่อหรือหากมีเครื่องหมายยัติภังค์ลบ (-) เดียวเป็นชื่อไฟล์) สำหรับบรรทัดที่มีการจับคู่กับรูปแบบที่กำหนด


สิ่งที่เกี่ยวกับgrep -Pz
Navaro

3

หากคุณยินดีที่จะใช้บริบทสิ่งนี้สามารถทำได้โดยการพิมพ์

grep -A 500 abc test.txt | grep -B 500 efg

สิ่งนี้จะแสดงทุกอย่างระหว่าง "abc" และ "efg" ตราบใดที่อยู่ภายใน 500 บรรทัดของกันและกัน


3

หากคุณต้องการคำทั้งสองอยู่ใกล้กันตัวอย่างเช่นไม่เกิน 3 บรรทัดคุณสามารถทำได้:

find . -exec grep -Hn -C 3 "abc" {} \; | grep -C 3 "efg"

ตัวอย่างเดียวกัน แต่กรองเฉพาะไฟล์ * .txt เท่านั้น:

find . -name *.txt -exec grep -Hn -C 3 "abc" {} \; | grep -C 3 "efg"

และคุณสามารถแทนที่grepคำสั่งด้วยegrepคำสั่งหากคุณต้องการค้นหาด้วยนิพจน์ทั่วไป


3

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

multiline:

sift -lm 'abc.*efg' testfile

เงื่อนไข:

sift -l 'abc' testfile --followed-by 'efg'

คุณสามารถระบุว่า 'efg' ต้องติดตาม 'abc' ภายในจำนวนบรรทัดที่แน่นอน:

sift -l 'abc' testfile --followed-within 5:'efg'

คุณสามารถค้นหาข้อมูลเพิ่มเติมเกี่ยวกับsift-tool.org


ฉันไม่คิดว่าตัวอย่างแรกจะใช้sift -lm 'abc.*efg' testfileงานได้เนื่องจากการจับคู่นั้นโลภมากและกลืนกินทุกบรรทัดจนกระทั่งefgไฟล์สุดท้าย
ดร. อเล็กซ์ RE

2

ในขณะที่ตัวเลือก sed เป็นวิธีที่ง่ายที่สุดและง่ายที่สุด แต่สายการบินเดียวของ LJ ไม่ได้เป็นแบบพกพาที่น่าเศร้าที่สุด ผู้ที่ติดอยู่กับ C เชลล์รุ่นหนึ่งจะต้องหลบหนีจากพวกเขา:

sed -e '/abc/,/efg/\!d' [file]

น่าเสียดายที่นี่ใช้ไม่ได้กับ bash และคณะ


1
#!/bin/bash
shopt -s nullglob
for file in *
do
 r=$(awk '/abc/{f=1}/efg/{g=1;exit}END{print g&&f ?1:0}' file)
 if [ "$r" -eq 1 ];then
   echo "Found pattern in $file"
 else
   echo "not found"
 fi
done

1

คุณสามารถใช้กรณี grep คุณไม่กระตือรือร้นในลำดับของรูปแบบ

grep -l "pattern1" filepattern*.* | xargs grep "pattern2"

ตัวอย่าง

grep -l "vector" *.cpp | xargs grep "map"

grep -lจะค้นหาไฟล์ทั้งหมดที่ตรงกับรูปแบบแรกและ xargs จะ grep สำหรับรูปแบบที่สอง หวังว่านี่จะช่วยได้


1
ที่จะเพิกเฉยต่อคำสั่ง "pattern1" และ "pattern2" ปรากฏในไฟล์แม้ว่า - OP จะระบุว่าเฉพาะไฟล์ที่ "pattern2" ปรากฏขึ้นหลังควรจะจับคู่ "pattern1"
Emil Lundberg

1

ด้วยเครื่องมือค้นหาเงิน :

ag 'abc.*(\n|.)*efg'

คล้ายกับคำตอบของผู้ถือแหวน แต่มีเอจีแทน ข้อได้เปรียบด้านความเร็วของเครื่องมือค้นหาเงินอาจเป็นไปได้ที่นี่


1
ดูเหมือนจะใช้งานไม่ได้ (echo abctest; echo efg)|ag 'abc.*(\n|.)*efg'ไม่ตรงกัน
phiresky

1

ฉันใช้สิ่งนี้เพื่อแยกลำดับ fasta จากไฟล์ fasta หลายอันโดยใช้ตัวเลือก -P สำหรับ grep:

grep -Pzo ">tig00000034[^>]+"  file.fasta > desired_sequence.fasta
  • P สำหรับการค้นหาตามภาษา Perl
  • z สำหรับการสิ้นสุดบรรทัดเป็น 0 ไบต์แทนที่จะขึ้นบรรทัดใหม่
  • o เพื่อจับภาพสิ่งที่ตรงกันตั้งแต่ grep ส่งคืนทั้งบรรทัด (ซึ่งในกรณีนี้เนื่องจากคุณทำ -z เป็นไฟล์ทั้งหมด)

หลักของ regexp คือสิ่ง[^>]ที่แปลว่า "ไม่เกินสัญลักษณ์"


0

เป็นทางเลือกที่จะตอบ Balu โมฮันของมันเป็นไปได้ที่จะบังคับใช้คำสั่งของรูปแบบที่ใช้เพียงgrep, headและtail:

for f in FILEGLOB; do tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep "pattern2" &>/dev/null && echo $f; done

อันนี้ไม่สวยมาก รูปแบบที่อ่านง่ายขึ้น:

for f in FILEGLOB; do
    tail $f -n +$(grep -n "pattern1" $f | head -n1 | cut -d : -f 1) 2>/dev/null \
    | grep -q "pattern2" \
    && echo $f
done

นี้จะพิมพ์ชื่อของไฟล์ทั้งหมดที่"pattern2"ปรากฏขึ้นหลังจาก"pattern1", หรือที่ทั้งสองปรากฏบนบรรทัดเดียวกัน :

$ echo "abc
def" > a.txt
$ echo "def
abc" > b.txt
$ echo "abcdef" > c.txt; echo "defabc" > d.txt
$ for f in *.txt; do tail $f -n +$(grep -n "abc" $f | head -n1 | cut -d : -f 1) 2>/dev/null | grep -q "def" && echo $f; done
a.txt
c.txt
d.txt

คำอธิบาย

  • tail -n +i- พิมพ์ทุกบรรทัดหลังจากที่iรวม
  • grep -n - เติมบรรทัดที่ตรงกันด้วยหมายเลขบรรทัด
  • head -n1 - พิมพ์เฉพาะแถวแรก
  • cut -d : -f 1- พิมพ์คอลัมน์ตัดแรกโดยใช้:เป็นตัวคั่น
  • 2>/dev/null- tailเอาต์พุตข้อผิดพลาดเงียบที่เกิดขึ้นหาก$()นิพจน์คืนค่าว่างเปล่า
  • grep -q- ปิดปากgrepและกลับมาทันทีหากพบการแข่งขันเนื่องจากเราสนใจเฉพาะรหัสทางออก

ใครช่วยอธิบายหน่อยได้&>ไหม? ฉันก็ใช้มันเหมือนกัน แต่ฉันไม่เคยเห็นมันบันทึกไว้ที่ไหน BTW ทำไมเราต้องเงียบ grep แบบนั้นจริง ๆ grep -qจะไม่ทำเคล็ดลับเช่นกัน?
ไวยากรณ์

1
&>บอกให้ bash เปลี่ยนเส้นทางทั้งเอาต์พุตมาตรฐานและข้อผิดพลาดมาตรฐานดูการ REDIRECTION ในคู่มือทุบตี คุณพูดถูกที่เราสามารถทำได้grep -q ...แทนที่จะทำเช่นนั้นgrep ... &>/dev/nullจับได้ดี!
Emil Lundberg

คิดอย่างนั้น จะกำจัดความเจ็บปวดจากการพิมพ์พิเศษจำนวนมากที่น่าอึดอัดใจ ขอบคุณสำหรับคำอธิบาย - ดังนั้นฉันต้องข้ามไปเล็กน้อยในคู่มือ (ค้นหาบางสิ่งที่เกี่ยวข้องกับมันจากระยะไกลมาก่อน) --- คุณอาจลองเปลี่ยนคำตอบของคุณ :)
syntaxerror

0

มันควรจะทำงานด้วยเหรอ!

perl -lpne 'print $ARGV if /abc.*?efg/s' file_list

$ARGVมีชื่อของไฟล์ปัจจุบันเมื่ออ่านจากfile_list /sตัวแก้ไขค้นหาข้ามบรรทัดใหม่


0

รูปแบบไฟล์*.shเป็นสิ่งสำคัญในการป้องกันไดเรกทอรีที่จะตรวจสอบ แน่นอนว่าการทดสอบบางอย่างก็สามารถป้องกันได้เช่นกัน

for f in *.sh
do
  a=$( grep -n -m1 abc $f )
  test -n "${a}" && z=$( grep -n efg $f | tail -n 1) || continue 
  (( ((${z/:*/}-${a/:*/})) > 0 )) && echo $f
done

The

grep -n -m1 abc $f 

ค้นหาการจับคู่สูงสุด 1 รายการและส่งคืน (-n) ชุดผ้าปูที่นอน หากพบการแข่งขัน (ทดสอบ -n ... ) ค้นหาการจับคู่สุดท้ายของ efg (ค้นหาทั้งหมดและใช้ท้ายด้วย tail -n 1)

z=$( grep -n efg $f | tail -n 1)

อื่นต่อไป

เนื่องจากผลลัพธ์เป็นสิ่งที่18:foofile.sh String alf="abc";เราต้องการตัดออกจาก ":" จนถึงจุดสิ้นสุด

((${z/:*/}-${a/:*/}))

ควรส่งคืนผลลัพธ์ที่เป็นบวกหากการจับคู่ครั้งสุดท้ายของนิพจน์ที่ 2 ผ่านการจับคู่ครั้งแรกของการจับคู่ครั้งแรก

echo $fจากนั้นเรารายงานชื่อไฟล์


0

ทำไมไม่ทำสิ่งที่ง่ายเหมือน:

egrep -o 'abc|efg' $file | grep -A1 abc | grep efg | wc -l

ส่งคืน 0 หรือจำนวนเต็มบวก

egrep -o (แสดงเฉพาะการจับคู่เคล็ดลับ: การจับคู่หลายรายการบนบรรทัดเดียวกันจะสร้างเอาต์พุตหลายบรรทัดราวกับว่าอยู่ในบรรทัดที่ต่างกัน)

  • grep -A1 abc (พิมพ์ abc และบรรทัดหลังจากนั้น)

  • grep efg | wc -l (0-n จำนวนบรรทัด efg ที่พบหลัง abc ในบรรทัดเดียวกันหรือต่อไปนี้ผลลัพธ์สามารถใช้ใน 'if ")

  • grep สามารถเปลี่ยนเป็น egrep เป็นต้นได้หากต้องการการจับคู่รูปแบบ


0

หากคุณมีการประมาณระยะทางระหว่าง 2 สตริง 'abc' และ 'efg' ที่คุณกำลังค้นหาคุณอาจใช้:

grep -r . -e 'abc' -A num1 -B num2 | grep 'efg'

ด้วยวิธีนี้ grep แรกจะส่งคืนบรรทัดด้วย 'abc' บวก # num1 บรรทัดหลังจากนั้นและ # num2 บรรทัดหลังจากนั้นและ grep ตัวที่สองจะกรองผ่านทั้งหมดเพื่อรับ 'efg' จากนั้นคุณจะรู้ว่าไฟล์ใดปรากฏร่วมกัน


0

ด้วยugrepเปิดตัวไม่กี่เดือนที่ผ่านมา:

ugrep 'abc(\n|.)+?efg'

เครื่องมือนี้เหมาะอย่างยิ่งสำหรับความเร็ว นอกจากนี้ยังรองรับ GNU / BSD / PCRE-grep

โปรดทราบว่าเราควรใช้การทำซ้ำอย่างเกียจคร้าน+?เว้นแต่ว่าคุณต้องการจับคู่ทุกบรรทัดefgเข้าด้วยกันจนเป็นบรรทัดสุดท้ายefgในไฟล์


-3

สิ่งนี้น่าจะใช้ได้:

cat FILE | egrep 'abc|efg'

หากมีมากกว่าหนึ่งรายการที่ตรงกันคุณสามารถกรองโดยใช้ grep -v


2
ในขณะที่ข้อมูลโค้ดยินดีต้อนรับและอาจให้ความช่วยเหลือบางอย่าง แต่ก็จะดีขึ้นอย่างมากหากมีคำอธิบายเกี่ยวกับวิธีการและสาเหตุที่แก้ไขปัญหาได้ โปรดจำไว้ว่าคุณกำลังตอบคำถามสำหรับผู้อ่านในอนาคตไม่ใช่เพียงแค่คนที่ถามตอนนี้! โปรดแก้ไขคำตอบของคุณเพื่อเพิ่มคำอธิบายและระบุข้อ จำกัด และสมมติฐานที่ใช้
Toby Speight

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