แสดงความคิดเห็นทุกบรรทัดจากบรรทัดที่ถูกคอมเม้นต์ล่าสุดไปยังบรรทัดด้วย 'foo'


12

พิจารณาไฟล์ข้อความusers.txt:

#alice
#bob
charlie
dotan
eric

ฉันต้องการที่จะแสดงความคิดเห็นทุกอย่างจาก (พิเศษ) เส้นแสดงความคิดเห็นสุดท้ายจนกว่า dotan(รวม) นี่คือผลลัพธ์ที่ได้:

#alice
#bob
#charlie
#dotan
eric

มีผู้แนะนำsedในการทำเช่นนี้หรือไม่ ฉันจะมีความสุขกับเครื่องมือใด ๆ ไม่ใช่แค่sedจริงๆ

ขณะนี้ฉันได้รับหมายเลขบรรทัดของบรรทัดที่ถูกคอมเม้นต์ล่าสุดดังนี้:

$ cat -n users.txt | grep '#' | tail -n1
  2 #bob

จากนั้นฉันเพิ่มหนึ่งและแสดงความคิดเห็นด้วยsed:

$ sed -i'' '3,/dotan/ s/^/#/' users.txt

ฉันรู้ว่าฉันสามารถฉลาดและใส่ทั้งหมดนี้เข้าด้วยกันbcเป็นหนึ่งซับ - น่าเกลียด แน่นอนต้องมีวิธีที่สะอาดกว่า?

คำตอบ:


5

เกี่ยวกับ

perl -pe '$n=1 if s/^dotan/#$&/; s/^[^#]/#$&/ unless $n==1;' file

หรือความคิดเดียวกันใน awk:

awk '(/^dotan/){a=1; sub(/^/,"#",$1)} (a!=1 && $1!~/^#/){sub(/^/,"#",$1);}1; ' file

7

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

sed '/^#/,/dotan/ s/^[^#]/#&/' file

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

tac file | sed '/dotan/,/^#/ s/^[^#]/#&/' | tac

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


4

คุณสามารถจัดการกับทั้งสองกรณี (บรรทัดที่ใส่ความคิดเห็นในบล็อกที่ต่อเนื่องเดี่ยวหรือกระจายระหว่างบรรทัดที่ไม่ใส่เครื่องหมายคอมเมนต์) ด้วยการsedเรียกใช้ครั้งเดียว:

sed '1,/PATTERN/{/^#/{x;1d;b};//!{H;/PATTERN/!{1h;d};//{x;s/\n/&#/g}}}' infile

กระบวนการนี้จะประมวลผลเฉพาะเส้นใน1,/PATTERN/ช่วง มันxเปลี่ยนพื้นที่ว่างไว้ pattern space ทุกครั้งที่บรรทัดถูกคอมเม้นต์ (ดังนั้นจะไม่มีบรรทัด commented มากกว่าหนึ่งบรรทัดในบัฟเฟอร์พัก) และต่อท้ายทุกบรรทัดที่ไม่ได้คอมเม้นต์กับHพื้นที่เก่า (เมื่ออยู่บนบรรทัดที่ 1 1dและ1hจำเป็นต้องลบลำดับแรกด้วยเช่นกัน บรรทัดว่างในบัฟเฟอร์พัก)
เมื่อมาถึงรูปแบบการจับคู่สายก็ยังผนวกไปยังHบัฟเฟอร์เก่า, E xเปลี่ยนแปลงบัฟเฟอร์แล้วแทนที่ทุก\nตัวอักษร ewline ในพื้นที่รูปแบบที่มี\newline และ#(นั่นคือทุกบรรทัดในพื้นที่รูปแบบในขณะนี้จะเริ่มต้นด้วย#, การรวมบรรทัดแรกเป็นบรรทัดแรกในพื้นที่พักจะเป็นบรรทัดที่ถูกคอมเม้นต์เสมอ)
ด้วยตัวอย่างinfile:

alice
#bob
bill
#charlie
ding
dong
dotan
jimmy
#garry

วิ่ง:

sed '1,/dotan/{                   # if line is in this range    -start c1
/^#/{                             # if line is commented        -start c2
x                                 # exchage hold space w. pattern space
1d                                # if 1st line, delete pattern space
b                                 # branch to end of script
}                                 #                             -end c2
//!{                              # if line is not commented    -start c3
H                                 # append to hold space
/dotan/!{                         # if line doesn't match dotan -start c4
1h                                # if 1st line, overwrite hold space
d                                 # delete pattern space
}                                 #                             -end c4
//{                               # if line matches dotan       -start c5
x                                 # exchage hold space w. pattern space
s/\n/&#/g                         # add # after each newline character
}                                 #                             -end c5
}                                 #                             -end c3
}' infile                         #                             -end c1

เอาท์พุท:

alice
#bob
bill
#charlie
#ding
#dong
#dotan
jimmy
#garry

ดังนั้นจึงเป็นการแสดงความคิดเห็นเฉพาะบรรทัดจาก (และไม่รวม) #charlieจนถึง (และรวมถึง) dotanและปล่อยให้บรรทัดอื่นไม่มีการแตะต้อง แน่นอนว่านี้จะถือว่ามีเสมออย่างน้อยหนึ่งความเห็นเส้นก่อนที่จะจับคู่สาย
PATTERNหากไม่ใช่กรณีนี้คุณสามารถเพิ่มการตรวจสอบเพิ่มเติมก่อนการเปลี่ยน:/^#/{s/\n/&#/g}


ขอบคุณฉันจะได้เรียนรู้จากคำตอบนี้น้อยมาก!
dotancohen

รอก่อนฉันต้องเมาแล้ว นี่ไม่เกี่ยวกับชุดความคิดเห็นสุดท้ายของบรรทัดหรือไม่ ไม่ฉันเข้าใจแล้ว ซีรี่ส์ล่าสุด + dotan ค่อนข้างฉลาดฉลาด
mikeserv

1
คุณมักจะพบคำถามที่ดีที่สุด Dotan ที่ถูกสาปให้ขว้างฉันสักครู่ - อาจจะยังอยู่ฉันยังไม่ได้ทดสอบเลย ขอบคุณดอน
mikeserv

2

นี่คืออีกsed:

sed  -e:n -e'/\n#.*\ndotan/!{$!{N;/^#/bn'      \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g' \
-et  -e\} -eP\;D <in >out

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

ป้อนคำอธิบายรูปภาพที่นี่

ขอโทษด้วยฉันไม่รู้ว่าทำไมฉันถึงทำอย่างนั้น แต่มันก็อยู่ในใจ

อย่างไรก็ตามการsedแพร่กระจายบัฟเฟอร์ระหว่างแต่ละบรรทัดที่ถูกคอมเม้นต์สุดท้ายในซีรีย์ใด ๆ ไม่เคยเก็บหนึ่งในบัฟเฟอร์ไว้มากกว่าที่จำเป็นในการติดตามเหตุการณ์ที่ถูกคอมเม้นต์ล่าสุดอย่างถูกต้องและหากใดก็ตามที่พบบรรทัดสุดท้ายในขณะที่พยายามทำgคำสั่งการดำเนินการ lobal สุดท้ายและสาขาtคือบัฟเฟอร์ทั้งหมดที่จะพิมพ์มิฉะนั้นมันจะลบPบรรทัดเหล่านั้นทั้งหมดที่มันออกจากบัฟเฟอร์ทันทีที่ทำ

ฉันคิดว่านี่เป็นสิ่งที่นำไปสู่ความคิดที่สอดคล้องกัน ...

printf %s\\n   \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric \
               \#alice \#bob charlie dotan eric |
sed  -e:n -e'l;/\n#.*\ndotan/!{$!{N;/^#/bn'     \
-eb  -e\} -e'/^#/s/\(\n\)\(dotan.*\)*/\1#\2/g'  \
-et  -e\} -eP\;D

#alice
#alice\n#bob$
#alice\n#bob\ncharlie$
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob\ncharlie\ndotan\neric\n#alice$
#bob\ncharlie\ndotan\neric\n#alice\n#bob$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie$
#bob\ncharlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
#bob
charlie\ndotan\neric\n#alice\n#bob\ncharlie\ndotan$
charlie
dotan\neric\n#alice\n#bob\ncharlie\ndotan$
dotan
eric\n#alice\n#bob\ncharlie\ndotan$
eric
#alice\n#bob\ncharlie\ndotan$
#alice
#bob\ncharlie\ndotan$
#bob\ncharlie\ndotan\neric$
#bob
#charlie
#dotan
eric

มีความแตกต่างเพียงอย่างเดียวระหว่างคำสั่งนี้กับคำสั่งด้านบนและนั่นคือlคำสั่ง ook ที่ด้านบน เมื่อเราเข้ามาlในsedพื้นที่ของรูปแบบการทำงานเราจะได้รับความคิดที่ดีขึ้นของสิ่งที่เกิดขึ้นเบื้องหลังและความเข้าใจที่ดีขึ้นของวิธีการที่จะนำความพยายามของมัน

ในกรณีนี้เราสามารถดูsedอินพุตสแต็กจนกระทั่งพบการเกิดขึ้นครั้งที่สองของ\n#.*\ndotanอินพุทและเมื่อมันเริ่มพิมพ์บรรทัดก่อนหน้าออกทีละครั้ง มันเจ๋งนะ ฉันได้เรียนรู้มากมายเกี่ยวกับสิ่งนี้


ดีมากขอบคุณ! ย่อหน้าสุดท้ายพร้อมคำอธิบายที่ยอดเยี่ยมฉันจะใช้เวลาเรียนรู้จากโพสต์นี้เช่นกัน Nice stack!
dotancohen

1
@dotancohen - นี่เป็นคำถามที่ดีจริงๆ ดูที่การแก้ไขเพื่อดูสแต็
mikeserv

2
Handle many dotansผมสังเกตเห็นในการแก้ไขประวัติศาสตร์รายการ ฉันแน่ใจว่านี่เป็นฝันร้ายที่เลวร้ายที่สุดของภรรยา
dotancohen

1
@dotancohen - ใช่นี่เป็นเรื่องที่ยากมาก สิ่งที่ชอบ#\ndotan\ndotanยากสำหรับสิ่งเหล่านี้ ฉันหมายความว่าเมื่อฉันพูดแบบนี้เป็นคำถามที่ดี ฉันคิดว่าฉันได้มันสมบูรณ์แบบ แต่ปัญหาหนึ่งที่คุณอาจเจอคือถ้าบล็อกความคิดเห็นของคุณถูกคั่นด้วย 1,000 บรรทัด - ซึ่งจะทำให้ช้าลง คุณอาจจะติดสิ่งที่เหมือนs/\n/&/150;tก่อนที่/\n#สิ่งแรกที่จะทำลายบัฟเฟอร์ถ้ามันครอบคลุม 150 บรรทัด และต่อไปอาจเป็นเพียงสิ่งที่เธอรอคอยมาตลอด !
mikeserv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.