ในการหลีกเลี่ยงตัวแปรที่จะใช้ทางด้านซ้ายและด้านขวาของ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, astGNU ล่าสุด, busybox ล่าสุด) หรือPCREs ที่มี-R( ssed) หรือRE Re Augmentedกับ-A/ -X( ast) ทั้งหมดมีตัวดำเนินการ RE พิเศษ
กฎพื้นฐานบางประการเมื่อจัดการกับข้อมูลที่กำหนดเอง:
- อย่าใช้
echo
- พูดตัวแปรของคุณ
- พิจารณาผลกระทบของโลแคล (โดยเฉพาะชุดอักขระ: เป็นสิ่งสำคัญที่คำสั่งescaping
sedจะทำงานในโลแคลเดียวกันกับsedคำสั่งโดยใช้สตริงที่ใช้Escape (และด้วยsedคำสั่งเดียวกัน) เป็นต้น)
- อย่าลืมเกี่ยวกับอักขระขึ้นบรรทัดใหม่ (ที่นี่คุณอาจต้องการตรวจสอบว่า
$lhsมีและดำเนินการใด ๆ )
ตัวเลือกอื่นคือการใช้perlแทนsedและส่งผ่านสตริงในสภาพแวดล้อมและใช้ตัวดำเนินการ\Q/ \E perlregexp สำหรับการรับสตริงอย่างแท้จริง:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl(โดยค่าเริ่มต้น) จะไม่ได้รับผลกระทบจากอักขระของโลแคลที่ตั้งค่าตามที่กล่าวไว้ข้างต้นจะพิจารณาเฉพาะสตริงเป็นอาร์เรย์ของไบต์โดยไม่สนใจว่าอักขระใด (ถ้ามี) ซึ่งอาจเป็นตัวแทนของผู้ใช้ ด้วยsedคุณสามารถทำสิ่งเดียวกันโดยแก้ไขโลแคลเป็นCด้วยLC_ALL=Cสำหรับsedคำสั่งทั้งหมด(แม้ว่าจะมีผลกับภาษาของข้อความแสดงข้อผิดพลาดหากมี)