ความหมายของอะไร: a; $! N; ในคำสั่ง sed หรือไม่?


11
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

sedคำสั่งด้านบนจะแทนที่อักขระบรรทัดใหม่ด้วยสตริง "string" แต่ฉันไม่รู้ความหมายของ:a;$!N;s/\n/string/;taคำพูดเดียว s/\n/string/ฉันรู้ว่าส่วนตรงกลาง แต่ฉันไม่ทราบหน้าที่ของส่วนแรก ( :a;$!N;) และส่วนสุดท้าย ( ta)


2
โปรดดูที่stackoverflow.com/questions/1251999/...
xiaodongjie

แล้วส่วนสุดท้ายล่ะ?
Avinash Raj

คำสั่ง "t" จะแตกสาขาเป็นเลเบลที่กำหนดชื่อหากคำสั่งการแทนที่ล่าสุดแก้ไขพื้นที่รูปแบบ
xiaodongjie

คำตอบ:


17

เหล่านี้คือsedคำสั่งที่เป็นความลับที่ยอมรับได้ โดยเฉพาะ (จากman sed):

: label ป้าย
         กำกับสำหรับคำสั่ง b และ t

t label
         หากในฐานะ /// ได้ทำการทดแทนที่ประสบความสำเร็จตั้งแต่บรรทัดอินพุตสุดท้ายถูกอ่านและตั้งแต่คำสั่ง t หรือ T ครั้งสุดท้ายให้แตกสาขาเป็นเลเบล หากไม่ระบุเลเบลให้แยกสาขาจนสุดสคริปต์

n N อ่าน / ต่อท้ายบรรทัดอินพุตถัดไปในพื้นที่รูปแบบ

ดังนั้นสคริปต์ที่คุณโพสต์สามารถแบ่งออกเป็น (ช่องว่างที่เพิ่มเข้ามาสำหรับ readbility):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

โดยทั่วไปสิ่งที่ทำสิ่งนี้สามารถเขียนใน pseudocode เป็น

while (not end of line){
    append current line to this one and replace \n with 'string'
}

คุณสามารถเข้าใจสิ่งนี้ได้ดีขึ้นเล็กน้อยด้วยตัวอย่างอินพุตที่ซับซ้อนมากขึ้น:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

ฉันไม่แน่ใจจริงๆว่าทำไมถึง!$ต้องการ เท่าที่ฉันสามารถบอกได้คุณสามารถเอาท์พุทเดียวกันกับ

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'

1
! $ คือการไม่ตรงกับบรรทัดใหม่ล่าสุด IMO
Braiam

@Braiam ไม่มากเกินไปแน่ใจเกี่ยวกับที่มันไม่ได้$! !$แต่ก็ยังอาจจะไม่!N $!
terdon

ผมพยายามที่จะแยกหน้า texinfo แต่ไม่พบการอ้างอิงถึงค่าหรือ!N $!ดังนั้นฉันยังคงคิดอยู่ว่าจะค้นหาว่าบรรทัดสุดท้ายเป็นบรรทัดใหม่หรือ EOF หรือไม่
Braiam

4
ฉันพยายามคิดว่า$!เป็น 'ช่วง' ที่อยู่พร้อมกับผู้ประกอบการเสริม postfix - ดังนั้น$!N(ทำNทุกที่ยกเว้นที่อยู่$) เป็นไวยากรณ์เดียวกันกับสิ่งที่ต้องการm,n!d(ลบทุกอย่างยกเว้นบรรทัดmไปn)
steeldriver

:เป็นแบบอะนาล็อกของgotoฉลากและในความเป็นจริง:เคยเป็นฉลากgotoในเชลล์ ธ อมป์สันดังนั้นผู้คนในวันนี้จึงคุ้นเคยกับการใช้ทั้ง sed และ Thompson shell
Sergiy Kolodyazhnyy

0

ผมโพสต์คำตอบนี้ตั้งแต่ผมเห็นจำนวนมากของความสับสนเกี่ยวกับเหตุผลที่บรรทัดสุดท้ายได้รับการยกเว้นเมื่อมีการดำเนินN(ผ่านสายที่อยู่สตริง$!) และเนื่องจาก OP ถูกสับสนเกี่ยวกับความหมายของ:a;$!N; ในคำสั่ง sedไม่เพียง แต่ในเฉพาะหนึ่งที่เขาโพสต์ .

ประโยชน์ของการใช้$!NแทนNไม่ได้เป็นหลักฐานในตัวอย่างที่เสนอ (โดย OP และโดย @terdon) เนื่องจากไม่มีคำสั่ง "สำคัญ" (อ่านต่อ) ดำเนินการในบรรทัดสุดท้ายหลังจากNคำสั่ง (แน่นอนผลลัพธ์จะเหมือนกันหากมีหนึ่งแถบที่ปิดที่บรรทัดนั้นอยู่)

ในตัวอย่างที่ซับซ้อนมากขึ้น (ตัวอย่างเช่นแทนที่this sentenceไฟล์ด้วยบางคำที่ปรากฏขึ้นในบางครั้งในหนึ่งบรรทัดและบางครั้งในสองบรรทัด) การยกเว้นบรรทัดสุดท้ายสำหรับNคำสั่งอาจเป็นสิ่งสำคัญ! หากบรรทัดสุดท้ายไม่ถูกแยกออกเมื่อเรียกใช้งานNจะพบsedกับEOFและออกทันทีเพื่อป้องกันคำสั่งที่ตามมาทั้งหมด (คำสั่งการแยกคำสั่งเช่นกันคือtและb) จะถูกดำเนินการ

ในตัวอย่างแบบง่ายเกินไปที่แสดงเราสามารถลบ$!และปล่อยให้sedล้มเหลวในการดำเนินการNและส่งคืนได้อย่างปลอดภัยเนื่องจากsคำสั่งที่ถูกยกเลิกจะไม่ทำอะไรเลยถ้ามันถูกเรียกใช้เนื่องจากไม่มี\nการจับคู่

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.