ฉันจะเห็นด้วยกับคุณ - มันอาจเป็นปัญหาทั่วไป สาธารณูปโภคส่วนกลางบางแห่งมีสิ่งอำนวยความสะดวกสำหรับการจัดการ
nl
nl
ยกตัวอย่างเช่นแยกเข้าสู่หน้าตรรกะเป็น-d
elimited โดยทั้งสองตัวละครส่วนคั่น สามเกิดขึ้นบนเส้นคนเดียวทั้งหมดบ่งชี้ถึงการเริ่มต้นของการที่หัว , สองร่างกายและหนึ่งส่วนท้ายส่วนท้ายมันจะแทนที่สิ่งเหล่านี้ที่พบในอินพุตด้วยบรรทัดว่างในเอาต์พุต - ซึ่งเป็นบรรทัดว่างเท่านั้นที่เคยพิมพ์
./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
การส่งออกอาจบิดเบือนตามค่าเริ่มต้น-d
elimiter \:
ผมได้เรียนรู้ที่จะต้องระมัดระวังมากขึ้นกับมันและเริ่มใช้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
นับ-s
idth + eparator len) * ช่องว่างที่ส่วนหัวของบรรทัดที่ไม่มีหมายเลข สิ่งนี้ช่วยให้คุณสามารถทำซ้ำเนื้อหาที่ไม่ได้หมายเลขโดยเปรียบเทียบกับเนื้อหาที่มีหมายเลข - และด้วยความพยายามเพียงเล็กน้อย เมื่อคุณพิจารณาว่าnl
จะแบ่งอินพุตออกเป็นส่วนตรรกะสำหรับคุณและคุณสามารถแทรก-s
trings ตามอำเภอใจที่หัวของแต่ละบรรทัดมันเป็นตัวเลขแล้วมันจะค่อนข้างง่ายในการจัดการเอาต์พุต:
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
สามารถe
xecute คำสั่งเชลล์ตามอำเภอใจสำหรับคุณโดยขึ้นอยู่กับคู่ที่ตรงกัน
sed '/^@@.*start$/!b
s//nl <<\\@@/;:l;N
s/\(\n@@\)[^\n]*end$/\1/
Tl;e' <infile
ด้านบนsed
รวบรวมอินพุตในพื้นที่รูปแบบจนกว่ามันจะเพียงพอที่จะผ่านการทดแทนได้สำเร็จT
และหยุดการb
ranching กลับไปที่อา:l
เบล เมื่อเป็นเช่นนั้นมันจะe
xecutes nl
พร้อมอินพุตที่แสดงเป็น<<
here-document สำหรับส่วนที่เหลือทั้งหมดของ pattern-space
เวิร์กโฟลว์เป็นดังนี้:
/^@@.*start$/!b
- ถ้า
^
ทั้งเส้น$
ไม่!
ไม่/
ตรงกับ/
รูปแบบดังกล่าวข้างต้นแล้วมันจะb
ranched จากสคริปต์และ autoprinted - ดังนั้นจากจุดนี้เราเป็นเพียงการทำงานร่วมกับชุดของเส้นที่เริ่มต้นด้วยรูปแบบที่
s//nl <<\\@@/
- ที่ว่างเปล่า
s//
ฟิลด์/
ยืนอยู่ในสำหรับที่อยู่ที่ผ่านมาsed
พยายามที่จะตรงกับ - เพื่อให้คำสั่งนี้ทดแทนทั้ง@@.*start
สายnl <<\\@@
แทน
:l;N
:
คำสั่งกำหนดฉลากสาขา - ที่นี่ฉันจะตั้งคนหนึ่งชื่อ:l
อาเบล N
คำสั่งต่อผนวกบรรทัดถัดไปของการป้อนข้อมูลไปยังพื้นที่รูปแบบตามด้วย\n
ตัวอักษร ewline นี่เป็นเพียงหนึ่งในไม่กี่วิธีในการรับ\n
ewline ในsed
พื้นที่รูปแบบ - \n
อักขระ ewline นั้นเป็นตัวคั่นที่แน่นอนสำหรับsed
ผู้ที่เคยทำมันมาชั่วขณะ
s/\(\n@@\)[^\n]*end$/\1/
s///
ubstitution นี้สามารถประสบความสำเร็จได้หลังจากพบการเริ่มต้นและเกิดขึ้นครั้งแรกหลังจากสิ้นสุดบรรทัด มันจะกระทำเฉพาะในพื้นที่รูปแบบที่\n
ewline สุดท้ายตามมาทันทีโดยการ@@.*end
ทำเครื่องหมายที่ส่วนท้ายสุด$
ของพื้นที่รูปแบบ เมื่อมันไม่กระทำจะแทนที่สตริงจับคู่ทั้งกับ\1
ครั้งแรกของ\(
กลุ่มหรือ\)
\n@@
Tl
T
สาขาคำสั่งคือป้ายกำกับ(หากมี)หากมีการเปลี่ยนตัวที่ประสบความสำเร็จไม่ได้เกิดขึ้นตั้งแต่ครั้งสุดท้ายที่สายการป้อนข้อมูลที่ถูกดึงเข้าไปในพื้นที่รูปแบบ(ที่ผมทำ w /N
) ซึ่งหมายความว่าทุกครั้งที่\n
ewline ต่อท้ายพื้นที่รูปแบบซึ่งไม่ตรงกับตัวคั่นปลายของคุณT
คำสั่ง est จะล้มเหลวและแยกกลับไปที่อา:l
เบลซึ่งส่งผลให้เกิดการsed
ดึงในส่วนN
ต่อขยายและวนซ้ำ
e
เมื่อทดแทนสำหรับการแข่งขันที่ได้คือประสบความสำเร็จและสคริปต์ที่ไม่ได้กลับสาขาล้มเหลวT
คือ, sed
จะe
xecute คำสั่งที่l
ooks เช่นนี้
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
จะp
rint ทุกบรรทัดจนกว่าจะพบเครื่องหมายเริ่มต้น - เมื่อq
uits อินพุตทั้งหมด -u
สวิตช์ nbuffered เป็นสิ่งจำเป็นสำหรับ GNU sed
เพราะมันสามารถ buffer ค่อนข้างตะกละตะกลามอย่างอื่น แต่ - ตามสเปค - อื่น ๆ POSIX sed
ควรทำงานโดยไม่มีการพิจารณาเป็นพิเศษใด ๆ - ตราบใดที่<infile
เป็นไฟล์ปกติ
เมื่อแรกsed
q
UITS เปลือกดำเนินการ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 คั่นส่วน