ในการหลีกเลี่ยงตัวแปรที่จะใช้ทางด้านซ้ายและด้านขวาของs
คำสั่งในsed
(ที่นี่$lhs
และ$rhs
ตามลำดับ) คุณต้องทำดังนี้:
escaped_lhs=$(printf '%s\n' "$lhs" | sed 's:[][\/.^$*]:\\&:g')
escaped_rhs=$(printf '%s\n' "$rhs" | sed 's:[\/&]:\\&:g;$!s/$/\\/')
sed "s/$escaped_lhs/$escaped_rhs/"
โปรดทราบว่า$lhs
ไม่สามารถมีอักขระขึ้นบรรทัดใหม่
นั่นคือบน LHS ให้หลีกเลี่ยงตัวดำเนินการ regexp ทั้งหมด ( ][.^$*
) ตัวละครหนีเอง ( \
) และตัวคั่น ( /
)
บน RHS คุณจะต้องยกเว้น&
ตัวคั่นเครื่องหมายแบ็กสแลชและอักขระขึ้นบรรทัดใหม่ (ซึ่งคุณทำโดยการแทรกแบ็กสแลชที่ท้ายแต่ละบรรทัดยกเว้นตัวสุดท้าย ( $!s/$/\\/
))
ที่ถือว่าคุณใช้/
เป็นตัวคั่นในsed
s
คำสั่งของคุณและคุณไม่ได้เปิดใช้งานExtended REsด้วย-r
(GNU sed
/ ssed
/ ast
/ busybox sed
) หรือ-E
(BSDs, ast
GNU ล่าสุด, busybox ล่าสุด) หรือPCREs ที่มี-R
( ssed
) หรือRE Re Augmentedกับ-A
/ -X
( ast
) ทั้งหมดมีตัวดำเนินการ RE พิเศษ
กฎพื้นฐานบางประการเมื่อจัดการกับข้อมูลที่กำหนดเอง:
- อย่าใช้
echo
- พูดตัวแปรของคุณ
- พิจารณาผลกระทบของโลแคล (โดยเฉพาะชุดอักขระ: เป็นสิ่งสำคัญที่คำสั่งescaping
sed
จะทำงานในโลแคลเดียวกันกับsed
คำสั่งโดยใช้สตริงที่ใช้Escape (และด้วยsed
คำสั่งเดียวกัน) เป็นต้น)
- อย่าลืมเกี่ยวกับอักขระขึ้นบรรทัดใหม่ (ที่นี่คุณอาจต้องการตรวจสอบว่า
$lhs
มีและดำเนินการใด ๆ )
ตัวเลือกอื่นคือการใช้perl
แทนsed
และส่งผ่านสตริงในสภาพแวดล้อมและใช้ตัวดำเนินการ\Q
/ \E
perl
regexp สำหรับการรับสตริงอย่างแท้จริง:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl
(โดยค่าเริ่มต้น) จะไม่ได้รับผลกระทบจากอักขระของโลแคลที่ตั้งค่าตามที่กล่าวไว้ข้างต้นจะพิจารณาเฉพาะสตริงเป็นอาร์เรย์ของไบต์โดยไม่สนใจว่าอักขระใด (ถ้ามี) ซึ่งอาจเป็นตัวแทนของผู้ใช้ ด้วยsed
คุณสามารถทำสิ่งเดียวกันโดยแก้ไขโลแคลเป็นC
ด้วยLC_ALL=C
สำหรับsed
คำสั่งทั้งหมด(แม้ว่าจะมีผลกับภาษาของข้อความแสดงข้อผิดพลาดหากมี)