ฉันจะผสมรูปแบบและช่วงตัวเลขใน 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ในตัวอย่างที่สองของคุณเพื่อให้มีเส้นที่มีรูปแบบ