ฉันจะเห็นด้วยกับคุณ - มันอาจเป็นปัญหาทั่วไป สาธารณูปโภคส่วนกลางบางแห่งมีสิ่งอำนวยความสะดวกสำหรับการจัดการ
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 คั่นส่วน