ฉันจะเห็นด้วยกับคุณ - มันอาจเป็นปัญหาทั่วไป สาธารณูปโภคส่วนกลางบางแห่งมีสิ่งอำนวยความสะดวกสำหรับการจัดการ
nl
nlยกตัวอย่างเช่นแยกเข้าสู่หน้าตรรกะเป็น-delimited โดยทั้งสองตัวละครส่วนคั่น สามเกิดขึ้นบนเส้นคนเดียวทั้งหมดบ่งชี้ถึงการเริ่มต้นของการที่หัว , สองร่างกายและหนึ่งส่วนท้ายส่วนท้ายมันจะแทนที่สิ่งเหล่านี้ที่พบในอินพุตด้วยบรรทัดว่างในเอาต์พุต - ซึ่งเป็นบรรทัดว่างเท่านั้นที่เคยพิมพ์
./infileฉันเปลี่ยนแปลงตัวอย่างของคุณจะรวมถึงส่วนอื่นและนำมาใส่ใน ดังนั้นดูเหมือนว่านี้:
line A
line B
@@inline-code-start
line X
line Y
line Z
@@inline-code-end
line C
line D
@@start
line M
line N
line O
@@end
จากนั้นฉันก็วิ่งต่อไปนี้:
sed 's/^@@.*start$/@@@@@@/
     s/^@@.*end$/@@/'  <infile |
nl -d@@ -ha -bn -w1
nlสามารถบอกได้ว่าจะสะสมสถานะข้ามหน้าตรรกะ แต่มันไม่ได้โดยค่าเริ่มต้น แต่จะกำหนดหมายเลขบรรทัดของอินพุตตามสไตล์และตามส่วนแทน ดังนั้น-haหมายถึงหมายเลขบรรทัดส่วนหัวทั้งหมดและ-bnหมายถึงไม่มีบรรทัดเนื้อ - ในขณะที่มันเริ่มออกมาในร่างกายสถานะ
จนกระทั่งผมได้เรียนรู้นี้ผมเคยใช้nlสำหรับการป้อนข้อมูลใด ๆ แต่หลังจากที่รู้ว่าnlการส่งออกอาจบิดเบือนตามค่าเริ่มต้น-delimiter \:ผมได้เรียนรู้ที่จะต้องระมัดระวังมากขึ้นกับมันและเริ่มใช้grep -nF ''สำหรับการป้อนข้อมูลทดสอบแทน แต่บทเรียนอื่น ๆ ที่ได้เรียนรู้ในวันนั้นก็คือnlสามารถนำไปใช้ประโยชน์อย่างมากในด้านอื่น ๆ - เช่นนี้ - ถ้าคุณเพียงแค่ปรับเปลี่ยนอินพุตเพียงเล็กน้อย - อย่างที่ฉันทำsedข้างบน
เอาท์พุท
  line A
  line B
1       line X
2       line Y
3       line Z
  line C
  line D
1       line M
2       line N
3       line O
ต่อไปนี้เป็นข้อมูลเพิ่มเติมเกี่ยวกับnl- คุณสังเกตเห็นว่าทุกบรรทัด แต่บรรทัดที่มีหมายเลขขึ้นต้นด้วยช่องว่างหรือไม่ เมื่อnlหมายเลขบรรทัดมันจะแทรกจำนวนอักขระลงในส่วนหัวของแต่ละอักขระ สำหรับบรรทัดเหล่านั้นมันไม่ได้เป็นตัวเลข - แม้จะเป็นช่องว่าง - มันตรงกับเยื้องเสมอโดยการแทรก (การ-wนับ-sidth + eparator len) * ช่องว่างที่ส่วนหัวของบรรทัดที่ไม่มีหมายเลข สิ่งนี้ช่วยให้คุณสามารถทำซ้ำเนื้อหาที่ไม่ได้หมายเลขโดยเปรียบเทียบกับเนื้อหาที่มีหมายเลข - และด้วยความพยายามเพียงเล็กน้อย เมื่อคุณพิจารณาว่าnlจะแบ่งอินพุตออกเป็นส่วนตรรกะสำหรับคุณและคุณสามารถแทรก-strings ตามอำเภอใจที่หัวของแต่ละบรรทัดมันเป็นตัวเลขแล้วมันจะค่อนข้างง่ายในการจัดการเอาต์พุต:
sed 's/^@@.*start$/@@@@@@/
     s/^@@.*end/@@/; t
     s/^\(@@\)\{1,3\}$/& /' <infile |
nl -d@@ -ha -bn -s' do something with the next line!
'
ภาพด้านบน ...
                                        line A
                                        line B
 1 do something with the next line!
line X
 2 do something with the next line!
line Y
 3 do something with the next line!
line Z
                                        line C
                                        line D
 1 do something with the next line!
line M
 2 do something with the next line!
line N
 3 do something with the next line!
line O
GNU sed
หากnlไม่ใช่แอปพลิเคชันเป้าหมายของคุณ GNU sedสามารถexecute คำสั่งเชลล์ตามอำเภอใจสำหรับคุณโดยขึ้นอยู่กับคู่ที่ตรงกัน
sed '/^@@.*start$/!b
     s//nl <<\\@@/;:l;N
     s/\(\n@@\)[^\n]*end$/\1/
Tl;e'  <infile
ด้านบนsedรวบรวมอินพุตในพื้นที่รูปแบบจนกว่ามันจะเพียงพอที่จะผ่านการทดแทนได้สำเร็จTและหยุดการbranching กลับไปที่อา:lเบล เมื่อเป็นเช่นนั้นมันจะexecutes nlพร้อมอินพุตที่แสดงเป็น<<here-document สำหรับส่วนที่เหลือทั้งหมดของ pattern-space
เวิร์กโฟลว์เป็นดังนี้:
- /^@@.*start$/!b- 
- ถ้า^ทั้งเส้น$ไม่!ไม่/ตรงกับ/รูปแบบดังกล่าวข้างต้นแล้วมันจะbranched จากสคริปต์และ autoprinted - ดังนั้นจากจุดนี้เราเป็นเพียงการทำงานร่วมกับชุดของเส้นที่เริ่มต้นด้วยรูปแบบที่
 
- s//nl <<\\@@/- 
- ที่ว่างเปล่าs//ฟิลด์/ยืนอยู่ในสำหรับที่อยู่ที่ผ่านมาsedพยายามที่จะตรงกับ - เพื่อให้คำสั่งนี้ทดแทนทั้ง@@.*startสายnl <<\\@@แทน
 
- :l;N- 
- :คำสั่งกำหนดฉลากสาขา - ที่นี่ฉันจะตั้งคนหนึ่งชื่อ- :lอาเบล- Nคำสั่งต่อผนวกบรรทัดถัดไปของการป้อนข้อมูลไปยังพื้นที่รูปแบบตามด้วย- \nตัวอักษร ewline นี่เป็นเพียงหนึ่งในไม่กี่วิธีในการรับ- \newline ใน- sedพื้นที่รูปแบบ -- \nอักขระ ewline นั้นเป็นตัวคั่นที่แน่นอนสำหรับ- sedผู้ที่เคยทำมันมาชั่วขณะ
 
- s/\(\n@@\)[^\n]*end$/\1/- 
- s///ubstitution นี้สามารถประสบความสำเร็จได้หลังจากพบการเริ่มต้นและเกิดขึ้นครั้งแรกหลังจากสิ้นสุดบรรทัด มันจะกระทำเฉพาะในพื้นที่รูปแบบที่- \newline สุดท้ายตามมาทันทีโดยการ- @@.*endทำเครื่องหมายที่ส่วนท้ายสุด- $ของพื้นที่รูปแบบ เมื่อมันไม่กระทำจะแทนที่สตริงจับคู่ทั้งกับ- \1ครั้งแรกของ- \(กลุ่มหรือ- \)- \n@@
 
- Tl- 
- Tสาขาคำสั่งคือป้ายกำกับ(หากมี)หากมีการเปลี่ยนตัวที่ประสบความสำเร็จไม่ได้เกิดขึ้นตั้งแต่ครั้งสุดท้ายที่สายการป้อนข้อมูลที่ถูกดึงเข้าไปในพื้นที่รูปแบบ(ที่ผมทำ w /- N) ซึ่งหมายความว่าทุกครั้งที่- \newline ต่อท้ายพื้นที่รูปแบบซึ่งไม่ตรงกับตัวคั่นปลายของคุณ- Tคำสั่ง est จะล้มเหลวและแยกกลับไปที่อา- :lเบลซึ่งส่งผลให้เกิดการ- sedดึงในส่วน- Nต่อขยายและวนซ้ำ
 
- e
 - 
- เมื่อทดแทนสำหรับการแข่งขันที่ได้คือประสบความสำเร็จและสคริปต์ที่ไม่ได้กลับสาขาล้มเหลว- Tคือ,- sedจะ- execute คำสั่งที่- looks เช่นนี้
 - nl <<\\@@\nline X\nline Y\nline Z\n@@$
 
 
คุณสามารถดูได้ด้วยตัวเองโดยแก้ไขบรรทัดสุดท้ายที่นั่นเพื่อให้มีลักษณะ Tl;l;eคุณสามารถดูนี้สำหรับตัวคุณเองโดยการแก้ไขบรรทัดสุดท้ายมีลักษณะเหมือน
มันพิมพ์:
line A
line B
     1  line X
     2  line Y
     3  line Z
line C
line D
     1  line M
     2  line N
     3  line O
while ... read
วิธีสุดท้ายในการทำเช่นนี้และอาจเป็นวิธีที่ง่ายที่สุดคือใช้การwhile readวนซ้ำ แต่ด้วยเหตุผลที่ดี เชลล์ - (โดยเฉพาะอย่างยิ่งbashเชลล์) - โดยทั่วไปแล้วจะมีความสามารถในการจัดการอินพุตในปริมาณมากหรือในลำธารที่มั่นคง สิ่งนี้สมเหตุสมผลเช่นกัน - หน้าที่ของเชลล์คือการจัดการอักขระอินพุตตามอักขระและเรียกใช้คำสั่งอื่น ๆ ซึ่งสามารถจัดการสิ่งที่ใหญ่กว่าได้
แต่ที่สำคัญเกี่ยวกับบทบาทของมันคือเชลล์จะต้องไม่ readใส่เข้าไปมากเกินไป - มันถูกระบุว่าไม่ให้บัฟเฟอร์อินพุตหรือเอาต์พุตไปยังจุดที่มันใช้งานมากหรือรีเลย์ไม่เพียงพอในเวลาที่คำสั่งที่มันเรียกนั้นขาดหายไป - ถึงไบต์ ดังนั้นreadสำหรับการทดสอบอินพุตที่ยอดเยี่ยม- returnข้อมูลเกี่ยวกับว่ามีอินพุทเหลืออยู่หรือไม่และคุณควรเรียกใช้คำสั่งถัดไปเพื่ออ่าน - แต่โดยทั่วไปแล้วไม่ใช่วิธีที่ดีที่สุดที่จะไป
อย่างไรก็ตามนี่คือตัวอย่างของวิธีการใช้งานread และคำสั่งอื่น ๆ เพื่อประมวลผลอินพุตโดยซิงค์:
while   IFS= read -r line        &&
case    $line in (@@*start) :;;  (*)
        printf %s\\n "$line"
        sed -un "/^@@.*start$/q;p";;
esac;do sed -un "/^@@.*end$/q;=;p" |
        paste -d: - -
done    <infile
สิ่งแรกที่เกิดขึ้นสำหรับการทำซ้ำแต่ละครั้งจะถูกreadดึงเข้าแถว หากประสบความสำเร็จหมายความว่าลูปยังไม่ได้กด EOF ดังนั้นในการcaseจับคู่กับตัวคั่นเริ่มต้นdoบล็อกจะถูกดำเนินการทันที อื่นprintfพิมพ์$lineมันreadและsedเรียกว่า
sedจะprint ทุกบรรทัดจนกว่าจะพบเครื่องหมายเริ่มต้น - เมื่อquits อินพุตทั้งหมด -uสวิตช์ nbuffered เป็นสิ่งจำเป็นสำหรับ GNU sedเพราะมันสามารถ buffer ค่อนข้างตะกละตะกลามอย่างอื่น แต่ - ตามสเปค - อื่น ๆ POSIX sedควรทำงานโดยไม่มีการพิจารณาเป็นพิเศษใด ๆ - ตราบใดที่<infileเป็นไฟล์ปกติ
เมื่อแรกsed qUITS เปลือกดำเนินการdoบล็อกของวง - ซึ่งเรียกอีกsedว่าพิมพ์ทุกบรรทัดจนกว่าจะเจอปลายเครื่องหมาย มันไปป์เอาท์พุทของมันpasteเพราะมันจะพิมพ์หมายเลขบรรทัดในบรรทัดของตัวเอง แบบนี้:
1
line M
2
line N
3
line O
pasteจากนั้นวาง:อักขระเหล่านั้นเข้าด้วยกันและผลลัพธ์ทั้งหมดจะเป็นดังนี้:
line A
line B
1:line X
2:line Y
3:line Z
line C
line D
1:line M
2:line N
3:line O
นี่เป็นเพียงตัวอย่าง - สิ่งใดก็ตามที่สามารถทำได้ในการทดสอบหรือบล็อกที่นี่ แต่ยูทิลิตี้แรกจะต้องไม่ใช้อินพุตมากเกินไป
สาธารณูปโภคทั้งหมดที่เกี่ยวข้องอ่านข้อมูลเดียวกัน - และพิมพ์ผลลัพธ์ของพวกเขา - ในทางกลับกัน ชนิดของสิ่งนี้อาจเป็นเรื่องยากที่จะได้รับการแขวนของ - เพราะสาธารณูปโภคที่แตกต่างกันจะ buffer มากกว่าคนอื่น ๆ - แต่คุณโดยทั่วไปสามารถพึ่งพาdd, headและsedที่จะทำสิ่งที่ถูกต้อง( แต่สำหรับ GNU sedคุณต้อง CLI สวิทช์)และ คุณควรจะสามารถที่จะพึ่งพาread- เพราะมันเป็นไปตามธรรมชาติช้ามาก และนั่นคือสาเหตุที่ลูปข้างต้นเรียกมันว่าเพียงครั้งเดียวต่อบล็อกอินพุต
               
              
nlไม่จำเป็นต้องมีรัฐสะสม ดูที่nl -dและตรวจสอบของคุณman/infoหน้าสำหรับข้อมูลเกี่ยวกับnl's คั่นส่วน