string - ultimo - Escapar de una cadena para un patrón de reemplazo sed
reemplazar cadena sed (14)
En mi script bash tengo una cadena externa (recibida del usuario), que debo usar en el patrón sed.
REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"
¿Cómo puedo escapar de la cadena $REPLACE
para que sea aceptada de forma segura por sed
como un reemplazo literal?
NOTA: KEYWORD
es una subcadena tonta sin coincidencias, etc. No es suministrada por el usuario.
Aquí hay un ejemplo de un AWK que usé hace un tiempo. Es un AWK que imprime nuevos AWKS. AWK y SED son similares, puede ser una buena plantilla.
ls | awk ''{ print "awk " "''"''"''" " {print $1,$2,$3} " "''"''"''" " " $1 ".old_ext > " $1 ".new_ext" }'' > for_the_birds
Parece excesivo, pero de alguna manera esa combinación de citas funciona para mantener el ''impreso como literales. Entonces, si recuerdo correctamente, las variables son simplemente rodeadas con citas como esta: "$ 1". Pruébalo, déjame saber cómo funciona con SED.
Basándome en las expresiones regulares de Pianosaurus, hice una función de bash que escapa tanto a la palabra clave como al reemplazo.
function sedeasy {
sed -i "s/$(echo $1 | sed -e ''s//([[//.*]/|/]/)///&/g'')/$(echo $2 | sed -e ''s/[//&]///&/g'')/g" $3
}
Así es como lo usas:
sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf
El comando sed le permite usar otros caracteres en lugar de /
como separador:
sed ''s#"http://www/.fubar/.com"#URL_FUBAR#g''
Las comillas dobles no son un problema.
Es un poco tarde para responder ... pero hay una forma mucho más sencilla de hacer esto. Simplemente cambie el delimitador (es decir, el carácter que separa los campos). Entonces, en lugar de s/foo/bar/
escribes s|bar|foo
.
Y, aquí está la manera fácil de hacer esto:
sed ''s|//*!50017 DEFINER=`snafu`@`localhost`/*/||g''
La salida resultante está desprovista de esa desagradable cláusula DEFINER.
Los únicos tres caracteres literales que se tratan especialmente en la cláusula de reemplazo son /
(para cerrar la cláusula), /
(para escapar de los caracteres, hacer una referencia inversa, & c.) Y &
(para incluir la coincidencia en el reemplazo). Por lo tanto, todo lo que necesitas hacer es escapar de esos tres personajes:
sed "s/KEYWORD/$(echo $REPLACE | sed -e ''s/////////g; s/////////g; s/&////&/g'')/g"
Ejemplo:
$ export REPLACE="''/"|///><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e ''s/////////g; s/////////g; s/&////&/g'')/g"
foo''"|//><&!bar
No olvide todo el placer que se produce con la limitación de shell alrededor "y ''
entonces (en ksh)
Var=">New version of /"content'' here <"
printf "%s" "${Var}" | sed "s/[&//////*//"'']///&/g'' | read -r EscVar
echo "Here is your /"text/" to change" | sed "s/text/${EscVar}/g"
Resulta que estás haciendo la pregunta incorrecta. También hice la pregunta equivocada. La razón por la que está mal es el comienzo de la primera oración: "En mi script de bash ...".
Tuve la misma pregunta y cometí el mismo error. Si está usando bash, no necesita usar sed para hacer reemplazos de cadenas (y es mucho más limpio usar la función de reemplazo integrada en bash).
En lugar de algo como, por ejemplo:
function escape-all-funny-characters() { UNKNOWN_CODE_THAT_ANSWERS_THE_QUESTION_YOU_ASKED; }
INPUT=''some long string with KEYWORD that need replacing KEYWORD.''
A="$(escape-all-funny-characters ''KEYWORD'')"
B="$(escape-all-funny-characters ''<funny characters here>'')"
OUTPUT="$(sed "s/$A/$B/g" <<<"$INPUT")"
Puedes usar las funciones de bash exclusivamente:
INPUT=''some long string with KEYWORD that need replacing KEYWORD.''
A=''KEYWORD''
B=''<funny characters here>''
OUTPUT="${INPUT//"$A"/"$B"}"
Si el caso es que está generando una contraseña aleatoria para pasar al patrón de reemplazo sed
, entonces elige tener cuidado con el conjunto de caracteres de la cadena aleatoria. Si elige una contraseña hecha codificando un valor como base64, entonces solo hay un carácter que es posible en base64 y también es un carácter especial en el patrón de reemplazo de sed
. Ese carácter es "/" y se elimina fácilmente de la contraseña que está generando:
# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e ''s/////g''`;
Si solo está buscando reemplazar el valor de Variable en el comando sed, simplemente elimine Ejemplo:
sed -i ''s/dev-/dev-$ENV/g'' test to sed -i s/dev-/dev-$ENV/g test
Solo escapa todo en la variable REPLACE:
echo $REPLACE | awk ''{gsub(".", "////&");print}''
Tengo una mejora sobre la función sedosa, que se romperá con caracteres especiales como la pestaña.
function sedeasy_improved {
sed -i "s/$(
echo "$1" | sed -e ''s//([[//.*]/|/]/)///&/g''
| sed -e ''s:/t://t:g''
)/$(
echo "$2" | sed -e ''s/[//&]///&/g''
| sed -e ''s:/t://t:g''
)/g" "$3"
}
Entonces, ¿qué es diferente? $1
y $2
envueltos en comillas para evitar expansiones de shell y preservar las pestañas o espacios dobles.
Tubería adicional | sed -e ''s:/t://t:g''
| sed -e ''s:/t://t:g''
(Me gusta :
como token) que transforma una pestaña en /t
.
Una forma más fácil de hacer esto es simplemente construir la cadena de antemano y usarla como un parámetro para sed
rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring test.txt
Use awk - es más limpio:
$ awk -v R=''//addr://file'' ''{ sub("THIS", R, $0); print $0 }'' <<< "http://file:/_THIS_/path/to/a/file//is///a// nightmare"
http://file:/_//addr:/file_/path/to/a/file//is///a// nightmare
Advertencia : Esto no considera nuevas líneas. Para una respuesta más detallada, vea esta pregunta SO en su lugar. (Gracias, Ed Morton y Niklas Peter)
Tenga en cuenta que escapar de todo es una mala idea. Sed necesita que muchos personajes se escapen para obtener su significado especial. Por ejemplo, si escapa un dígito en la cadena de reemplazo, se convertirá en una referencia inversa.
Como dijo Ben Blank, solo hay tres caracteres que deben escaparse en la cadena de reemplazo (se escapa a sí mismos, barra diagonal para el final de la instrucción y & para reemplazar a todos):
sed -e ''s/[//&]///&/g''
Si alguna vez necesitas escapar de la cadena KEYWORD
, la siguiente es la que necesitas:
sed -e ''s/[]//$*.^[]///&/g''
Recuerde, si utiliza un carácter que no sea /
como delimitador, deberá reemplazar la barra en las expresiones anteriores con el carácter que está utilizando. Vea el comentario de PeterJCLaw para explicación.
Editado: debido a algunos casos de esquina que anteriormente no se tenían en cuenta, los comandos anteriores han cambiado varias veces. Compruebe el historial de edición para más detalles.