Para escapar de las variables que se utilizarán en el lado izquierdo y en el lado derecho de un s
comando en sed
(aquí $lhs
y $rhs
respectivamente), debe hacer lo siguiente:
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/"
Tenga en cuenta que $lhs
no puede contener un carácter de nueva línea.
Es decir, en el LHS, escapa de todos los operadores regexp ( ][.^$*
), el propio carácter de escape ( \
) y el separador ( /
).
En el RHS, solo necesita escapar &
, el separador, la barra diagonal inversa y el carácter de nueva línea (lo que hace insertando una barra diagonal inversa al final de cada línea excepto la última ( $!s/$/\\/
)).
Eso supone que lo usa /
como separador en sus sed
s
comandos y que no habilita los RE extendidos con -r
(GNU sed
/ ssed
/ ast
/ busybox sed
) o -E
(BSD, ast
GNU reciente, busybox reciente) o PCRE con -R
( ssed
) o RE aumentados con -A
/ -X
( ast
) que todos tienen operadores RE adicionales.
Algunas reglas básicas cuando se trata de datos arbitrarios:
- No usar
echo
- cita tus variables
- considere el impacto de la configuración regional (especialmente su conjunto de caracteres: es importante que los comandos de escape
sed
se ejecuten en la misma configuración regional que el sed
comando usando las cadenas de escape (y con el mismo sed
comando) por ejemplo)
- no se olvide del carácter de nueva línea (aquí es posible que desee verificar si
$lhs
contiene alguno y tomar medidas).
Otra opción es usar en perl
lugar de sed
y pasar las cadenas en el entorno y usar los operadores \Q
/ \E
perl
regexp para tomar cadenas literalmente:
A="$lhs" B="$rhs" perl -pe 's/\Q$ENV{A}\E/$ENV{B}/g'
perl
(por defecto) no se verá afectado por el conjunto de caracteres de la configuración regional ya que, en lo anterior, solo considera las cadenas como matrices de bytes sin preocuparse por qué caracteres (si los hay) pueden representar para el usuario. Con sed
, puede lograr lo mismo arreglando la configuración regional C
con LC_ALL=C
para todos los sed
comandos (aunque eso también afectará el idioma de los mensajes de error, si los hay).