ภาพรวมในหลาย ๆ ที่เป็นประโยชน์คำตอบที่มีอยู่ , ครบครันด้วยคำอธิบาย :
ตัวอย่างที่นี่ใช้กรณีการใช้งานที่ง่ายขึ้น: แทนที่คำว่า 'foo' ด้วย 'bar' ในบรรทัดแรกที่ตรงกันเท่านั้น
เนื่องจากการใช้สตริง ANSI C-ยกมา ( $'...'
)เพื่อให้เส้นที่นำเข้าตัวอย่างbash
, ksh
หรือzsh
จะถือว่าเป็นเปลือก
GNU sed
เท่านั้น:
เบน Hoffstein ของ anwswerแสดงให้เราเห็นว่า GNU ให้ขยายไปยังสเปคสำหรับ POSIXsed
ที่ช่วยให้ต่อไปนี้รูปแบบที่ 2 ที่อยู่ : 0,/re/
( re
หมายถึงการแสดงออกปกติโดยพลการที่นี่)
0,/re/
อนุญาตให้ regex จับคู่กับบรรทัดแรกได้เช่นกัน กล่าวอีกนัยหนึ่ง: ที่อยู่ดังกล่าวจะสร้างช่วงจากบรรทัดที่ 1 ถึงและรวมถึงบรรทัดที่ตรงกับre
- ไม่ว่าจะre
เกิดขึ้นในบรรทัดที่ 1 หรือในบรรทัดที่ตามมาใด ๆ
- ตัดกับส่วนนี้ด้วยรูปแบบที่สอดคล้องกับ POSIX
1,/re/
ซึ่งสร้างช่วงที่จับคู่จากบรรทัดที่ 1 จนถึงและรวมถึงบรรทัดที่จับคู่re
ในบรรทัดถัดไป กล่าวอีกนัยหนึ่ง: สิ่งนี้จะไม่ตรวจจับการเกิดขึ้นครั้งแรกของการre
แข่งขันหากมันเกิดขึ้นในบรรทัดที่1และยังป้องกันการใช้ชวเลขและ//
เพื่อนำ regex ที่ใช้ล่าสุดมาใช้ใหม่ (ดูจุดถัดไป) 1
หากคุณรวม0,/re/
อยู่กับs/.../.../
(ทดแทน) โทรที่ใช้เหมือนกันแสดงออกปกติคำสั่งของคุณจะมีประสิทธิภาพเพียงดำเนินการเปลี่ยนตัวในครั้งแรกre
ที่สายการแข่งขัน
sed
ให้ความสะดวกสบายทางลัดสำหรับการนำการแสดงออกปกตินำมาใช้มากที่สุดเมื่อเร็ว ๆ นี้ : มีที่ว่างเปล่า//
คู่คั่น,
$ sed '0,/foo/ s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
คุณลักษณะ POSIX เท่านั้นเท่านั้นsed
เช่น BSD (macOS)sed
(จะทำงานร่วมกับGNU sed
):
เนื่องจาก0,/re/
ไม่สามารถใช้รูปแบบและ1,/re/
จะไม่ตรวจสอบre
ถ้ามันเกิดขึ้นที่จะเกิดขึ้นในบรรทัดแรกมาก (ดูด้านบน) การจัดการพิเศษสำหรับสายที่ 1 จะต้อง
คำตอบของ MikhailVSกล่าวถึงเทคนิคใส่ตัวอย่างที่เป็นรูปธรรมที่นี่:
$ sed -e '1 s/foo/bar/; t' -e '1,// s//bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar # only 1st match of 'foo' replaced
Unrelated
2nd foo
3rd foo
บันทึก:
//
ทางลัดว่างเปล่า regex มีการใช้งานสองครั้งที่นี่: หนึ่งครั้งสำหรับจุดสิ้นสุดของช่วงและหนึ่งครั้งในการs
โทร ในทั้งสองกรณี regex foo
จะถูกนำมาใช้ซ้ำโดยปริยายทำให้เราไม่ต้องทำซ้ำซึ่งทำให้ทั้งรหัสสั้นและบำรุงรักษาได้มากกว่า
POSIX sed
ต้องการขึ้นบรรทัดใหม่ที่เกิดขึ้นจริงหลังจากที่ฟังก์ชั่นบางอย่างเช่นหลังจากที่ชื่อของป้ายหรือแม้กระทั่งการละเลยของตนเป็นกรณีที่มีt
ที่นี่ การแบ่งสคริปต์อย่างมีกลยุทธ์ออกเป็นหลาย-e
ตัวเลือกเป็นทางเลือกในการใช้การขึ้นบรรทัดใหม่จริง: วาง-e
สคริปต์แต่ละอันที่บรรทัดใหม่จะต้องไป
1 s/foo/bar/
แทนที่foo
ในบรรทัดที่ 1 เท่านั้นหากพบว่ามี หากเป็นเช่นนั้นให้t
แยกไปที่ส่วนท้ายของสคริปต์ (ข้ามคำสั่งที่เหลืออยู่บนบรรทัด) ( t
ฟังก์ชั่นแยกสาขาไปยังป้ายกำกับเฉพาะเมื่อการs
โทรล่าสุดทำการทดแทนจริงในกรณีที่ไม่มีป้ายกำกับเช่นกรณีที่นี่จุดสิ้นสุดของสคริปต์จะถูกแยกเป็น)
ที่เกิดขึ้นเมื่อช่วงที่อยู่1,//
ซึ่งปกติจะพบว่าเกิดขึ้นครั้งแรกที่เริ่มต้นจากสาย 2จะไม่ตรงและช่วงจะไม่ได้2
รับการดำเนินการเพราะอยู่จะถูกประเมินเมื่อบรรทัดปัจจุบันที่มีอยู่แล้ว
ในทางกลับกันหากไม่มีการจับคู่ในบรรทัดที่ 1 1,//
จะถูกป้อนและจะค้นหาการจับคู่แรกที่แท้จริง
ผลกระทบสุทธิเป็นเช่นเดียวกับ GNU sed
's 0,/re/
: เพียงเกิดขึ้นครั้งแรกจะถูกแทนที่ไม่ว่าจะเกิดขึ้นในบรรทัดที่ 1 หรืออื่น ๆ
วิธีที่ไม่ใช่ช่วง
คำตอบ Potong ของแสดงให้เห็นถึงห่วงเทคนิคที่หลีกเลี่ยงความจำเป็นสำหรับช่วงที่ ; เนื่องจากเขาใช้ไวยากรณ์GNU ต่อ sed
ไปนี้เป็นสิ่งที่เทียบเท่ากับPOSIX :
เทคนิควนรอบ 1: ในนัดแรกทำการทดแทนจากนั้นเข้าสู่วงที่พิมพ์เส้นที่เหลือตามที่เป็นอยู่ :
$ sed -e '/foo/ {s//bar/; ' -e ':a' -e '$!{n;ba' -e '};}' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
ห่วงเทคนิค 2 สำหรับไฟล์ smallish เพียง : อ่านการป้อนข้อมูลทั้งหมดลงในหน่วยความจำแล้วทำการเปลี่ยนตัวเดียวกับมัน
$ sed -e ':a' -e '$!{N;ba' -e '}; s/foo/bar/' <<<$'1st foo\nUnrelated\n2nd foo\n3rd foo'
1st bar
Unrelated
2nd foo
3rd foo
1 1.61803ให้ตัวอย่างของสิ่งที่เกิดขึ้นกับ1,/re/
โดยมีและไม่มีสิ่งต่อไปนี้s//
:
- sed '1,/foo/ s/foo/bar/' <<<$'1foo\n2foo'
ผลตอบแทน$'1bar\n2bar'
; กล่าวคือทั้งสองบรรทัดได้รับการอัปเดตเนื่องจากหมายเลขบรรทัด1
ตรงกับบรรทัดที่ 1 และ regex /foo/
- จุดสิ้นสุดของช่วง - จากนั้นจะค้นหาเฉพาะการเริ่มต้นในบรรทัดถัดไป ดังนั้นทั้งสองบรรทัดจะถูกเลือกในกรณีนี้และทำการs/foo/bar/
ทดแทนในทั้งสองบรรทัด
- sed '1,/foo/ s//bar/' <<<$'1foo\n2foo\n3foo'
ล้มเหลว : ด้วยsed: first RE may not be empty
(BSD / macOS) และsed: -e expression #1, char 0: no previous regular expression
(GNU) เนื่องจากในขณะที่บรรทัดที่ 1 กำลังถูกประมวลผล (เนื่องจากหมายเลขบรรทัดที่1
เริ่มต้นช่วง) ยังไม่มีการใช้ regex ดังนั้น//
ไม่ได้อ้างถึงอะไร
ด้วยข้อยกเว้นของ GNU sed
's พิเศษ0,/re/
ไวยากรณ์ใด ๆช่วงที่เริ่มต้นด้วยหมายเลขบรรทัด//
ได้อย่างมีประสิทธิภาพป้องกันการใช้