ฉันจะผสมรูปแบบและช่วงตัวเลขใน sed (หรือเครื่องมือที่คล้ายกัน - awk เป็นต้น) ได้อย่างไร สิ่งที่ฉันต้องการทำคือจับคู่บางบรรทัดในไฟล์และลบ n บรรทัดถัดไปก่อนที่จะดำเนินการต่อและฉันต้องการทำเช่นนั้นเป็นส่วนหนึ่งของไปป์ไลน์
ฉันจะผสมรูปแบบและช่วงตัวเลขใน sed (หรือเครื่องมือที่คล้ายกัน - awk เป็นต้น) ได้อย่างไร สิ่งที่ฉันต้องการทำคือจับคู่บางบรรทัดในไฟล์และลบ n บรรทัดถัดไปก่อนที่จะดำเนินการต่อและฉันต้องการทำเช่นนั้นเป็นส่วนหนึ่งของไปป์ไลน์
คำตอบ:
ฉันจะไปที่นี้
ในการลบ 5 บรรทัดหลังรูปแบบ (รวมถึงเส้นที่มีรูปแบบ):
sed -e '/pattern/,+5d' file.txt
ในการลบ 5 บรรทัดหลังรูปแบบ (ไม่รวมบรรทัดที่มีรูปแบบ):
sed -e '/pattern/{n;N;N;N;N;d}' file.txt
/pattern/,+5
กำหนดช่วงซึ่งเริ่มต้นด้วยบรรทัดที่มี "รูปแบบ" ( /pattern/
) และสิ้นสุด 5 บรรทัดในภายหลัง ( +5
) อักขระสุดท้ายd
คือคำสั่งสำหรับเรียกใช้ในแต่ละบรรทัดในช่วงนั้นซึ่งก็คือ "ลบ" ในสูตรที่สองแทนที่จะจับคู่ช่วงจะจับคู่เฉพาะที่บรรทัดที่มีรูปแบบ ( /pattern/
) จากนั้นเรียกใช้ชุดคำสั่ง: {n;N;N;N;N;d}
ซึ่งโดยทั่วไปจะพิมพ์บรรทัดถัดไป ( n
) จากนั้นอ่านและทิ้ง 4 บรรทัดถัดไป ( N;N;N;N;d
).
sed -e '/pattern/{n;N;N;N;N;d;}' file.txt
something
ทำ: regex ที่ขยายการพกพา POSIX อยู่sed -E '/^something$/,$d'
ที่ไหน -E
ไม่มีส่วนขยาย GNU (เช่นบน macOS):
หากต้องการลบ 5 บรรทัดหลังรูปแบบ (รวมถึงเส้นที่มีรูปแบบ)
sed -e '/pattern/{N;N;N;N;d;}'
เพิ่ม-i ''
เพื่อแก้ไขในสถานที่
awk
วิธีแก้ปัญหาง่ายๆ:
สมมติว่าการแสดงออกปกติจะใช้สำหรับการหาเส้นจับคู่จะถูกเก็บไว้ในตัวแปรเปลือกและนับจากบรรทัดที่จะข้ามไปใน$regex
$count
หากควรข้ามบรรทัดที่ตรงกันด้วย ( ข้าม$count + 1
เส้น):
... | awk -v regex="$regex" -v count="$count" \
'$0 ~ regex { skip=count; next } --skip >= 0 { next } 1'
หากไม่ควรข้าม$count
เส้นที่ตรงกัน( เส้นหลังการแข่งขันถูกข้ามไป):
... | awk -v regex="$regex" -v count="$count" \
'$0 ~ regex { skip=count; print; next } --skip >= 0 { next } 1'
คำอธิบาย:
-v regex="$regex" -v count="$count"
กำหนดawk
ตัวแปรตามตัวแปรเชลล์ที่มีชื่อเดียวกัน$0 ~ regex
ตรงกับสายงานที่สนใจ
{ skip=count; next }
เริ่มต้นการนับการข้ามและดำเนินการต่อไปยังบรรทัดถัดไปโดยข้ามบรรทัดที่ตรงกันอย่างมีประสิทธิภาพ ในโซลูชันที่ 2 print
ก่อนหน้านี้จะnext
ช่วยให้แน่ใจว่าไม่มีการข้าม--skip >= 0
ลดจำนวนการข้ามและดำเนินการหากเป็น (นิ่ง)> = 0 หมายความว่าควรข้ามเส้นที่อยู่ในมือ{ next }
ไปยังบรรทัดถัดไปโดยข้ามบรรทัดปัจจุบันอย่างมีประสิทธิภาพ1
เป็นชวเลขที่ใช้กันทั่วไปสำหรับ{ print }
; นั่นคือบรรทัดปัจจุบันถูกพิมพ์อย่างเรียบง่าย
1
เทียบเท่ากับ{ print }
นั้น1
ถูกตีความว่าเป็นรูปแบบบูลีนที่ตามนิยามมักจะประเมินว่าเป็นจริงซึ่งหมายความว่าการดำเนินการที่เกี่ยวข้อง (บล็อก) จะถูกดำเนินการโดยไม่มีเงื่อนไข เนื่องจากไม่มีการดำเนินการที่เกี่ยวข้องในกรณีนี้awk
ค่าเริ่มต้นคือการพิมพ์บรรทัดสิ่งนี้อาจได้ผลสำหรับคุณ:
cat <<! >pattern_number.txt
> 5 3
> 10 1
> 15 5
> !
sed 's|\(\S*\) \(\S*\)|/\1/,+\2{//!d}|' pattern_number.txt |
sed -f - <(seq 21)
1
2
3
4
5
9
10
12
13
14
15
21
pattern_number.txt
คือไฟล์ 2 คอลัมน์ที่มีรูปแบบที่จะจับคู่ในคอลัมน์ที่ 1 และในลำดับที่ 2 จำนวนบรรทัดที่จะข้าม sed
คำสั่งแรกแปลงไฟล์เป็นsed
สคริปต์ที่ดำเนินการจับคู่และข้ามที่สอดคล้องกัน สคริปต์นั้นถูกจัดเตรียมผ่าน-f
และ stdin ( -
) ไปยังsed
คำสั่งที่2 sed
คำสั่งที่2 ดำเนินการกับไฟล์อินพุต ad-hoc ตัวอย่างที่สร้างขึ้นจากเอาต์พุตของseq 21
เพื่อแสดงให้เห็นว่าทำงานได้
ใช้ Perl
$ cat delete_5lines.txt
1
2
3
4
5 hello
6
7
8
9
10
11 hai
$ perl -ne ' BEGIN{$y=1} $y=$. if /hello/ ; print if $y==1 or $.-$y > 5 ' delete_5lines.txt
1
2
3
4
11 hai
$
โซลูชันนี้ช่วยให้คุณส่ง "n" เป็นพารามิเตอร์และจะอ่านรูปแบบของคุณจากไฟล์:
awk -v n=5 '
NR == FNR {pattern[$0]; next}
{
for (patt in pattern) {
if ($0 ~ patt) {
print # remove if you want to exclude a matched line
for (i=0; i<n; i++) getline
next
}
}
print
}
' file.with.patterns -
ไฟล์ชื่อ "-" หมายถึง stdin สำหรับ awk ดังนั้นจึงเหมาะสำหรับไปป์ไลน์ของคุณ
+N
รูปแบบนี้เป็นส่วนขยาย GNU เปลี่ยนรูปแบบแรกn
เป็นN
ในตัวอย่างที่สองของคุณเพื่อให้มีเส้นที่มีรูปแบบ