นี่เป็นคำถามเก่า แต่ไม่มีคำตอบใดที่จะกล่าวถึงการดำเนินการนอกเหนือจากs/from/to/
รายละเอียดมากนัก
รูปแบบทั่วไปของsed
คำสั่งคือ
*address* *action*
โดยที่อยู่อาจเป็นช่วงนิพจน์ทั่วไปหรือช่วงหมายเลขบรรทัด (หรือว่างซึ่งในกรณีนี้การดำเนินการจะถูกนำไปใช้กับทุกบรรทัดอินพุต) ตัวอย่างเช่น
sed '1,4d' file
จะลบบรรทัดที่ 1 ถึง 4 (ที่อยู่คือช่วงหมายเลขบรรทัด1,4
และการดำเนินการคือd
คำสั่งลบ); และ
sed '/ick/,$s/foo/bar/' file
จะแทนที่การเกิดขึ้นครั้งแรกfoo
ด้วยbar
ในบรรทัดใด ๆ ระหว่างการจับคู่ครั้งแรกใน regex ick
และจุดสิ้นสุดของไฟล์ (ที่อยู่คือช่วง/ick/,$
และการดำเนินการคือs
คำสั่งแทนที่s/foo/bar/
)
ในบริบทนี้หากick
มาจากตัวแปรคุณสามารถทำได้
sed "/$variable/,\$s/foo/bar/"
(สังเกตการใช้เครื่องหมายคำพูดคู่แทนคำพูดเดี่ยวเพื่อให้เชลล์สามารถสอดแทรกตัวแปรและความจำเป็นในการอ้างเครื่องหมายดอลลาร์ตามตัวอักษรภายในเครื่องหมายคำพูดคู่) แต่ถ้าตัวแปรมีเครื่องหมายทับคุณจะได้รับข้อผิดพลาดทางไวยากรณ์ (เชลล์ขยายตัวแปรจากนั้นส่งสตริงผลลัพธ์ไปยังsed
; ดังนั้นsed
เห็นเฉพาะข้อความตามตัวอักษร - ไม่มีแนวคิดเกี่ยวกับตัวแปรของเชลล์)
วิธีแก้คือการใช้ตัวคั่นอื่น (ซึ่งแน่นอนว่าคุณต้องสามารถใช้อักขระที่ไม่สามารถเกิดขึ้นในค่าของตัวแปรได้) แต่ไม่เหมือนในs%foo%bar%
กรณีนี้คุณต้องใช้แบ็กสแลชก่อนตัวคั่นหากคุณต้องการใช้ตัวอื่น ตัวคั่นมากกว่าค่าเริ่มต้น/
:
sed "\\%$variable%,\$s/foo/bar/" file
(ภายในเครื่องหมายคำพูดเดียวแบ็กสแลชเดียวก็เพียงพอแล้ว) หรือคุณสามารถแยกทุกเครื่องหมายทับในค่า ไวยากรณ์เฉพาะนี้คือ Bash เท่านั้น:
sed "/${variable//\//\\/}/,\$s/foo/bar/" file
หรือถ้าคุณใช้เปลือกอื่นให้ลอง
escaped=$(echo "$variable" | sed 's%/%\\/%g')
sed "s/$escaped/,\$s/foo/bar/" file
เพื่อความชัดเจนหาก$variable
มีสตริง1/2
คำสั่งข้างต้นจะเทียบเท่ากับ
sed '\%1/2%,$s/foo/bar/' file
ในกรณีแรกและ
sed '/1\/2/,$s/foo/bar/' file
ในวินาที