ลบบรรทัดที่มีสตริงที่แน่นอนและบรรทัดต่อไปนี้


70

ฉันใช้สิ่งนี้

cat foo.txt | sed '/bar/d'

เพื่อลบบรรทัดที่มีสตริงbarในไฟล์

ฉันต้องการ แต่จะลบเส้นที่และสายโดยตรงหลังจากที่มัน โดยเฉพาะอย่างยิ่งในsed, awkหรือเครื่องมืออื่น ๆ ที่มีอยู่ใน MinGW32

มันเป็นสิ่งที่ตรงกันข้ามกับสิ่งที่ฉันสามารถเข้าgrepกับ-Aและ-Bพิมพ์บรรทัดที่ตรงกันรวมถึงบรรทัดก่อน / หลังบรรทัดที่ตรงกัน

มีวิธีง่าย ๆ เพื่อให้บรรลุหรือไม่


2
สำหรับข้อมูลเท่านั้น: ฉันกำลังวิเคราะห์บันทึกที่มีสองรายการ ดังนั้นฉันต้องการค้นหารายการที่ตรงกับรูปแบบและลบออกเป็นบรรทัดถัดไป ดังนั้นฉันไม่จำเป็นต้องจัดการกับคู่ที่ตรงกัน แต่ขอบคุณสำหรับความสมบูรณ์ของคำตอบของคุณ!
jakub.g

คำตอบ:


74

หากคุณมี GNU sed (เช่น Linux หรือ Cygwin ที่ไม่ได้ฝังตัว):

sed '/bar/,+1 d'

หากคุณมีbarสองบรรทัดติดต่อกันสิ่งนี้จะลบบรรทัดที่สองโดยไม่ต้องวิเคราะห์ ตัวอย่างเช่นถ้าคุณมีไฟล์ 3 บรรทัดbar/ bar/ fooที่fooสายจะอยู่


1
+1 สำหรับความยาว :) ในตัวอย่างเฉพาะของฉันฉันไม่มีbars ต่อเนื่องดังนั้นอันนี้จำง่ายสุด
jakub.g

11
sed '/bar/d'หากคุณเพียงแค่ต้องการ "ลบบรรทัดที่มีสตริงที่แน่นอน" และไม่ใช่ต่อไป
AJP

ถ้าฉันต้องการลบบรรทัดทั้งหมดหลังจากคณิตศาสตร์แล้ว?
Pandya

1
@Pandya นั้นแตกต่างกัน คุณสามารถใช้เช่นsed '/math/q'
Gilles

1
@AK หากคุณต้องการลบเส้นที่ตรงกันมันง่ายยิ่งขึ้น:sed '/bar/d'
Gilles

16

หากbarอาจเกิดขึ้นในสายติดต่อกันคุณสามารถทำ:

awk '/bar/{n=2}; n {n--; next}; 1' < infile > outfile

ซึ่งสามารถดัดแปลงเพื่อลบมากกว่า 2 บรรทัดโดยการเปลี่ยน 2 ข้างต้นด้วยจำนวนบรรทัดที่จะลบรวมถึงการจับคู่หนึ่ง

หากไม่เป็นเช่นนั้นก็สามารถทำได้อย่างง่ายดายsedด้วยโซลูชัน @MichaelRollinsหรือ:

sed '/bar/,/^/d' < infile > outfile

บวกอื่น ๆ ในการแก้ปัญหา AWK คือว่าผมสามารถแทนที่ด้วย/bar/ /bar|baz|whatever/ในsedไวยากรณ์นั้นดูเหมือนจะไม่ทำงาน
jakub.g

@ jakub.g ฉันมี GNU sed (v4.4 ทันที) ไม่แน่ใจเกี่ยวกับคนอื่น สิ่งที่ฉันรู้คือมันใช้ไวยากรณ์พื้นฐานของการแสดงออกปกติ "พื้นฐาน" นี่คือสาเหตุที่ตัวอย่างของคุณใช้งานไม่ได้ เพื่อให้ได้สิ่งที่คุณต้องการคุณสามารถใส่แบ็กสแลชไว้ข้างหน้าของแต่ละบรรทัดในแนวตั้งหรือคุณสามารถขอsedให้ใช้นิพจน์ปกติ "ขยาย" ข้อมูลเพิ่มเติมที่นี่: gnu.org/software/sed/manual/html_node/... โปรดทราบว่าสิ่งนี้ใช้ได้กับgrepเช่นกัน echo $'0a\n1b\n2c' | sed '/0a\|1b/d'นี่คือตัวอย่างการทำงานของตัวเอง:
Victor Yarema

12

ฉันไม่คล่องใน sed แต่มันง่ายที่จะทำใน awk:

awk '/bar/{getline;next} 1' foo.txt 

สคริปต์ awk อ่าน: สำหรับบรรทัดที่มีแถบให้รับบรรทัดถัดไป (getline) จากนั้นข้ามการประมวลผลที่ตามมาทั้งหมด (ถัดไป) รูปแบบที่ 1 ที่ท้ายพิมพ์บรรทัดที่เหลือ

ปรับปรุง

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

awk '/bar/ {while (/bar/ && getline>0) ; next} 1' foo.txt 

ตอนนี้เราอ่านต่อไปเพื่อข้ามแถบ / / ทั้งหมด


1
ในการทำซ้ำgrep -A100% คุณต้องจัดการกับจำนวนbarบรรทัดที่ต่อเนื่องกันอย่างถูกต้อง (โดยการลบทั้งบล็อกและ 1 บรรทัดหลังจาก)
jw013

7

คุณจะต้องใช้ประโยชน์จากความสามารถด้านการเขียนสคริปต์ของ sed เพื่อทำสิ่งนี้ให้สำเร็จ

$ sed -e '/bar/ { 
 $!N
 d
 }' sample1.txt

ข้อมูลตัวอย่าง:

$ cat sample1.txt 
foo
bar
biz
baz
buz

คำสั่ง "N" ผนวกบรรทัดถัดไปของอินพุตเข้ากับพื้นที่รูปแบบ สิ่งนี้รวมกับบรรทัดจากการจับคู่รูปแบบ (/ บาร์ /) จะเป็นบรรทัดที่คุณต้องการลบ คุณสามารถลบได้ตามปกติด้วยคำสั่ง "d"


ฉันจะพิมพ์บรรทัดใหม่ในคอนโซลได้อย่างไร หรือนี่เป็นสคริปต์เท่านั้น?
jakub.g

@ jakub.g: กับ GNU sed:sed -e '/bar/{N;d}' sample1.txt
Cyrus

2

หากสายใดก็ตามที่ตามหลังการแข่งขันควรถูกลบออกไปsedโปรแกรมของคุณจะต้องพิจารณาการแข่งขันที่ต่อเนื่องกัน กล่าวอีกนัยหนึ่งถ้าคุณลบบรรทัดหลังการแข่งขันซึ่งตรงกับแล้วคุณอาจจะลบบรรทัดตามนั้นเช่นกัน

มันมีการใช้งานที่เพียงพอ - แต่คุณต้องมองหลังนิดหน่อย

printf %s\\n     0 match 2 match match \
                 5 6 match match match \
                 10 11 12 match 14 15  |
sed -ne'x;/match/!{g;//!p;}'

0
6
11
12
15

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

ดังนั้นsedตรวจสอบบรรทัดก่อนหน้าเพื่อหาคู่ที่ตรงกันmatchและหาก!ไม่พบนิพจน์ทั้งสองใน{ฟังก์ชัน}จะถูกเรียกใช้ sedจะget พื้นที่ถือโดยการเขียนทับพื้นที่รูปแบบ - ซึ่งหมายความว่าบรรทัดปัจจุบันเป็นแล้วทั้งในการระงับและรูปแบบช่องว่าง - แล้วมันจะ//ตรวจสอบสำหรับการแข่งขันที่จะแสดงออกปกติรวบรวมมากที่สุดเมื่อเร็ว ๆ นี้ - match- และถ้ามันไม่ได้matchมัน ถูกprinted

ซึ่งหมายความว่าจะพิมพ์บรรทัดต่อเมื่อไม่มีและบรรทัดก่อนหน้านั้นทันทีจะไม่พิมพ์ นอกจากนี้ยังมองเห็นการแลกเปลี่ยนที่ไม่จำเป็นสำหรับลำดับของesmatch matchmatch

หากคุณต้องการรุ่นที่สามารถปล่อยจำนวนบรรทัดที่เกิดขึ้นหลังจากmatchนั้นจะต้องใช้งานเพิ่มอีกเล็กน้อย:

printf %s\\n    1 2 3 4 match  \
                match match 8  \
                9 10 11 12 13  \
                14 match match \
                17 18 19 20 21 |
sed -net -e'/match/{h;n;//h;//!H;G;s/\n/&/5;D;}' -ep

... แทนที่ 5 ด้วยจำนวนบรรทัด(รวมถึงบรรทัดที่ตรงกัน)ที่คุณต้องการลบ ...


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