Để thoát các biến được sử dụng ở phía bên trái và bên phải của s
lệnh trong sed
(ở đây $lhs
và $rhs
tương ứng), bạn sẽ làm:
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/"
Lưu ý rằng $lhs
không thể chứa một ký tự dòng mới.
Đó là, trên LHS, thoát tất cả các toán tử regrec ( ][.^$*
), ký tự thoát ( \
) và dấu phân cách ( /
).
Trên RHS, bạn chỉ cần thoát &
, dấu phân cách, dấu gạch chéo ngược và ký tự dòng mới (mà bạn thực hiện bằng cách chèn dấu gạch chéo ngược ở cuối mỗi dòng trừ dấu cuối ( $!s/$/\\/
)).
Giả sử bạn sử dụng /
làm dấu phân cách trong các sed
s
lệnh của mình và rằng bạn không kích hoạt REs mở rộng với -r
(GNU sed
/ ssed
/ ast
/ busybox sed
) hoặc -E
(BSD, ast
GNU gần đây, busybox gần đây) hoặc PCRE với -R
( ssed
) hoặc RE Augmented với -A
/ -X
( ast
) tất cả đều có thêm toán tử RE.
Một vài quy tắc cơ bản khi xử lý dữ liệu tùy ý:
- Đừng dùng
echo
- trích dẫn các biến của bạn
- xem xét tác động của miền địa phương (đặc biệt là bộ ký tự của nó: điều quan trọng là các lệnh thoát
sed
được chạy trong cùng một miền với sed
lệnh sử dụng các chuỗi thoát ( sed
ví dụ với cùng một lệnh)
- đừng quên ký tự dòng mới (ở đây bạn có thể muốn kiểm tra xem
$lhs
có chứa bất kỳ và thực hiện hành động nào không).
Một tùy chọn khác là sử dụng perl
thay vì sed
và truyền các chuỗi trong môi trường và sử dụng các toán tử \Q
/ \E
perl
regrec để lấy chuỗi theo nghĩa đen:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl
(theo mặc định) sẽ không bị ảnh hưởng bởi bộ ký tự của miền địa phương, như ở trên, nó chỉ coi các chuỗi là mảng byte mà không quan tâm đến ký tự nào (nếu có) mà chúng có thể đại diện cho người dùng. Với sed
, bạn có thể đạt được như vậy bằng cách sửa chữa các miền địa phương để C
có LC_ALL=C
cho tất cả sed
các lệnh (mặc dù đó cũng sẽ ảnh hưởng đến ngôn ngữ của thông báo lỗi, nếu có).