วิธีการ grep -v และแยกบรรทัดถัดไปหลังการแข่งขัน?


15

จะกรอง 2 บรรทัดสำหรับแต่ละบรรทัดที่ตรงกับ grep regex ได้อย่างไร
นี่คือการทดสอบขั้นต่ำของฉัน:

SomeTestAAAA
EndTest
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestAABC
EndTest
SomeTestACDF
EndTest

และเห็นได้ชัดว่าฉันพยายามเช่นgrep -vA 1 SomeTestAAที่ไม่ทำงาน

ผลลัพธ์ที่ต้องการคือ:

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

grep -v 'SomeTextAA' | uniq?
DarkHeart

คำตอบ:


14

คุณสามารถใช้grepกับ-P(PCRE):

grep -P -A 1 'SomeTest(?!AA)' file.txt

(?!AA)เป็นความกว้างศูนย์รูปแบบเชิงลบ lookahead สร้างความมั่นใจว่าจะไม่มีการหลังจากที่AASomeTest

ทดสอบ:

$ grep -P -A 1 'SomeTest(?!AA)' file.txt 
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

ตัวหนีสำหรับจุดคืออะไร ชอบ Some.Test.AA?
Behrooz

1
@Behrooz หนีจุดโดย\.เพื่อให้grep -P -A 1 'SomeTest\.(?!AA)' file.txtหรือgrep -P -A 1 'SomeTest(?!\.AA)' file.txt
heemayl

วิธีนี้ใช้ได้ผลในกรณีเฉพาะเนื่องจากในกลุ่มตัวอย่างSomeTest*\nEndTestOPs มีคู่ของดังนั้นคุณจะgrepping จับคู่ทุกบรรทัดSomeTest*แต่ไม่SomeTestAA+ บริบทหนึ่งบรรทัดหลังการจับคู่ เพิ่มบรรทัดเพิ่มเติมลงในอินพุต (เช่นเพิ่มบรรทัดfoobarหลังแต่ละEndTestบรรทัด) จากนั้นลองอีกครั้ง
don_crissti

1
@don_crissti นั่นเป็นเรื่องจริงฉันได้ทำไปแล้ว
Behrooz

@Behrooz - สนใจที่จะแบ่งปันกับเราว่าคุณทำงานอย่างไรและอาจตอบความคิดเห็นของฉันภายใต้คำถามของคุณ?
don_crissti

4

นี่คือsedวิธีแก้ปัญหา (โดย-nไม่มีการพิมพ์อัตโนมัติ) ที่ทำงานกับอินพุตโดยพลการ:

sed -n '/SomeTestAA/!p          # if line doesn't match, print it
: m                             # label m
//{                             # if line matches
$!{                             # and if it's not the last line
n                               # empty pattern space and read in the next line
b m                             # branch to label m (so n is repeated until a
}                               # line that's read in no longer matches) but
}                               # nothing is printed
' infile

ดังนั้นด้วยการป้อนข้อมูลเช่น

SomeTestAAXX
SomeTestAAYY
+ one line
SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestAABC
+ another line
SomeTestTHREE
EndTest
SomeTestAA
+ yet another line

วิ่ง

sed -n -e '/SomeTestAA/!p;: m' -e '//{' -e '$!{' -e 'n;b m' -e '}' -e'}' infile

เอาท์พุท

SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestTHREE
EndTest

นั่นคือจะลบบรรทัดที่grep -A1 SomeTestAA infileจะเลือก:

SomeTestAAXX
SomeTestAAYY
+ one line
--
SomeTestAABC
+ another line
--
SomeTestAA
+ yet another line

น่าสนใจ ฉันไม่ได้ตระหนักว่าการจับคู่// /SomeTestAA/ฉันคิดว่าในกรณีนี้มันจะเข้าคู่กับนิพจน์ที่ถูกทำให้ยุ่งเหยิง: /SomeTestAA/!. (+1)
Peter.O

@ Peter.O - ขอบคุณ! ไม่ตามข้อมูลจำเพาะRE ที่ว่างเปล่าควรตรงกับREล่าสุดที่ใช้ในคำสั่งสุดท้ายเสมอ !ไม่ได้เป็นส่วนหนึ่งของเรื่องก็เป็นsedสิ่งที่
don_crissti

3

คุณอาจโชคดีขึ้นกับบางสิ่งที่ดูภูมิภาคหลายบรรทัดเป็นระเบียนเดียว มีสิ่งsgrepที่ฉันไม่ได้ใช้มาก

นอกจากนี้ยังมี awk ซึ่งคุณสามารถตั้งค่าตัวคั่นเรคคอร์ดอินพุตและตัวแยกเร็กคอร์ดเอาต์พุตเป็นสิ่งที่คุณต้องการ

pat="^SomeTestAA"
awk  'BEGIN{ RS=ORS="\nEndTest\n"} !/'"$pat/" foo

โปรแกรม awk ส่วนใหญ่เป็นแบบเสนอราคาเดี่ยว แต่ฉันเปลี่ยนเป็นอัญประกาศคู่ท้ายเพื่อให้$patตัวแปรเชลล์สามารถขยายได้


awk -vpat="^SomeTestAA" -vRS="\nEndTest\n" 'BEGIN{ ORS=RS } $0 !~ pat' file
Peter.O

3

เลือกหนึ่งคือการใช้pErl compatible regular eXPRESSION grep:

pcregrep -Mv 'SomeTestAA.*\n' file

ตัวเลือก-Mอนุญาตให้รูปแบบจับคู่มากกว่าหนึ่งบรรทัด


1
@don_crissti ทั้งสองบรรทัดจะถูกลบ ข้อมูลจำเพาะของ OP ไม่ครอบคลุมถึงกรณีนี้
jimmij

มันค่อนข้างชัดเจนว่าตัวอย่าง & คำถามของ OPs ไม่ครอบคลุมกรณีดังกล่าวฉันแค่อยากรู้ว่ามันทำงานอย่างไร (ฉันไม่คุ้นเคยกับ pcre) เพราะมีจำนวนบรรทัดติดต่อกันที่ตรงกับที่ใช้งานได้ บรรทัดบริบทด้วย) และด้วยจำนวนบรรทัดที่ต่อเนื่องกันที่ตรงกันซึ่งล้มเหลว (ไม่ลบบรรทัดบริบทหลังจาก)
don_crissti

ระบุว่า (GNU) grepรองรับ PCRE แล้ว (ผ่าน-Pตัวเลือก) ประโยชน์ของการใช้pcregrepคืออะไร
arielf

@arielf grepไม่สนับสนุน-Mตัวเลือก
jimmij

1

คุณสามารถใช้คำสั่งsedของGNU dเพื่อลบบรรทัดและนำหน้าด้วย/pat/,+Nเพื่อเลือกบรรทัดที่ตรงกับรูปแบบและบรรทัดN ที่ตามมา ในกรณีของคุณN = 1 เนื่องจากคุณต้องการที่จะลบบรรทัดถัดไปเดียวหลังจากบรรทัดที่ตรงกัน:

sed -e '/SomeTestAAAA/,+1d'

1

ใช้มาตรฐานsed:

$ sed '/SomeTestAA/{ N; d; }' file
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

sedสคริปต์แยกสายแฟ้มใส่โดยสายและเมื่อเส้นตรงกับรูปแบบSomeTestAAทั้งสองsedคำสั่งการแก้ไขNและdจะดำเนินการ Nคำสั่งผนวกบรรทัดถัดไปของการป้อนข้อมูลไปยังพื้นที่รูปแบบ (บัฟเฟอร์ที่sedสามารถแก้ไข) และdลบพื้นที่รูปแบบและเริ่มรอบถัดไป


1

พยายามใช้คำสั่งด้านล่าง sed และทำงานได้ดี

คำสั่ง

sed  '/SomeTestAA/,+1d' filename

เอาท์พุต

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