Escape une chaîne pour un modèle de remplacement sed
dans mon script bash j'ai une chaîne externe (reçue de l'utilisateur), que je devrais utiliser dans le modèle sed.
REPLACE="<funny characters here>"
sed "s/KEYWORD/$REPLACE/g"
Comment puis-je échapper à la chaîne $REPLACE
pour qu'elle soit acceptée en toute sécurité par sed
comme un remplacement littéral?
NOTE: le KEYWORD
est un substrat muet sans correspondance etc. Il n'est pas fourni par l'utilisateur.
14 réponses
Warning : ceci fait et non considèrent newlines. Pour une réponse plus détaillée, voir cette SO-question à la place. (Merci, Ed Morton & Niklas Pierre)
notez que tout échapper est une mauvaise idée. Sed a besoin de beaucoup de caractères pour être échappé à obtenir leur signification particulière. Par exemple, si vous échappez à un chiffre de la chaîne de remplacement, celui-ci se retournera vers un backreference.
comme Ben Blank l'a dit, il n'y a que trois caractères qui doivent être échappés dans la chaîne de remplacement (échappés eux-mêmes, barre oblique avant pour la fin de la déclaration et & pour remplacer tous):
sed -e 's/[\/&]/\&/g'
si vous avez besoin d'échapper à la chaîne KEYWORD
, la suivante est celle dont vous avez besoin:
sed -e 's/[]\/$*.^[]/\&/g'
rappelez-vous, si vous utilisez un caractère autre que /
comme délimiteur, vous devez remplacer la barre oblique dans le expressions ci-dessus avec le caractère que vous utilisez. Voir le commentaire de PeterJCLaw pour une explication.
modifié: en raison de certains cas de coin qui n'ont pas été pris en compte auparavant, les commandes ci-dessus ont changé plusieurs fois. Consultez l'historique d'édition pour plus de détails.
la commande sed vous permet d'utiliser d'autres caractères au lieu de /
comme séparateur:
sed 's#"http://www\.fubar\.com"#URL_FUBAR#g'
les doubles guillemets ne sont pas un problème.
les trois seuls caractères littéraux qui font l'objet d'un traitement spécial dans la clause de remplacement sont /
(pour fermer la clause), \
(pour échapper aux caractères, rétroréférence, etc.), et &
(pour inclure la correspondance dans le remplacement). Par conséquent, tout ce que vous devez faire est d'échapper à ces trois caractères:
sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\/\\/g; s/\//\\//g; s/&/\\&/g')/g"
exemple:
$ export REPLACE="'\"|\/><&!"
$ echo fooKEYWORDbar | sed "s/KEYWORD/$(echo $REPLACE | sed -e 's/\/\\/g; s/\//\\//g; s/&/\\&/g')/g"
foo'"|\/><&!bar
basé sur les expressions régulières du Pianosaurus, j'ai créé une fonction de bash qui échappe à la fois au mot-clé et au remplacement.
function sedeasy {
sed -i "s/$(echo | sed -e 's/\([[\/.*]\|\]\)/\&/g')/$(echo | sed -e 's/[\/&]/\&/g')/g"
}
Voici comment vous l'utilisez:
sedeasy "include /etc/nginx/conf.d/*" "include /apps/*/conf/nginx.conf" /etc/nginx/nginx.conf
il est un peu tard pour répondre... mais il y a une façon beaucoup plus simple de le faire. Il suffit de changer le délimiteur (i.e., le caractère qui sépare les champs). Donc, au lieu de s/foo/bar/
vous écrivez s|bar|foo
.
et, voici le moyen facile de le faire:
sed 's|/\*!50017 DEFINER=`snafu`@`localhost`\*/||g'
la sortie résultante est dépourvue de cette clause de définition désagréable.
il s'avère que vous posez la mauvaise question. J'ai aussi posé la mauvaise question. La raison pour laquelle il est erroné est le début de la première phrase: "dans mon bash script...".
j'ai eu la même question et fait la même erreur. Si vous utilisez bash, vous n'avez pas besoin d'utiliser sed pour effectuer des remplacements de chaînes (et c'est le nettoyeur much pour utiliser la fonctionnalité de remplacement intégrée dans bash).
au lieu de quelque chose comme, par exemple:
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")"
vous pouvez utiliser les fonctionnalités de bash exclusivement:
INPUT='some long string with KEYWORD that need replacing KEYWORD.'
A='KEYWORD'
B='<funny characters here>'
OUTPUT="${INPUT//"$A"/"$B"}"
Utiliser awk - c'est plus propre:
$ awk -v R='//addr:\file' '{ sub("THIS", R, "151900920"); print "151900920" }' <<< "http://file:\_THIS_/path/to/a/file\is\\a\ nightmare"
http://file:\_//addr:\file_/path/to/a/file\is\\a\ nightmare
voici un exemple d'un AWK que j'ai utilisé il y a un certain temps. C'est un AWK qui imprime de nouveaux AWKS. AWK et SED étant similaires, il peut être un bon modèle.
ls | awk '{ print "awk " "'"'"'" " {print ,,} " "'"'"'" " " ".old_ext > " ".new_ext" }' > for_the_birds
il semble excessif, mais d'une certaine façon cette combinaison de citations fonctionne pour garder le ' imprimé comme littérales. Alors, si je me souviens bien, les vaiables sont juste entourées de citations comme celle-ci: "$1". Essayez, dites-moi comment ça marche avec SED.
j'ai une amélioration par rapport à la fonction sedeasy, qui va rompre avec les caractères spéciaux comme tab.
function sedeasy_improved {
sed -i "s/$(
echo "" | sed -e 's/\([[\/.*]\|\]\)/\&/g'
| sed -e 's:\t:\t:g'
)/$(
echo "" | sed -e 's/[\/&]/\&/g'
| sed -e 's:\t:\t:g'
)/g" ""
}
alors, qu'est-ce qui est différent? et
enveloppés dans des guillemets pour éviter les agrandissements de la coque et préserver les onglets ou les espaces doubles.
tuyauterie supplémentaire | sed -e 's:\t:\t:g'
(j'aime :
comme jeton) qui transforme un onglet dans \t
.
si le cas se trouve que vous générez un mot de passe aléatoire pour passer à sed
remplacer le motif, alors vous choisissez d'être prudent sur quel ensemble de caractères dans la chaîne aléatoire. Si vous choisissez un mot de passe fait en encodant une valeur comme base64, alors il n'y a que le caractère is qui est à la fois possible dans base64 et est aussi un caractère spécial dans sed
remplacer le motif. Ce caractère est "/", et est facilement supprimé du mot de passe que vous générez:
# password 32 characters log, minus any copies of the "/" character.
pass=`openssl rand -base64 32 | sed -e 's/\///g'`;
Juste d'échapper à tout dans le REMPLACER varible:
echo $REPLACE | awk '{gsub(".", "\\&");print}'
n'oubliez pas tout le plaisir qui se produit avec la limitation de la coque autour de " et
so (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"
si vous cherchez juste à remplacer la valeur de la Variable dans la commande sed alors il suffit de supprimer Exemple:
sed -i 's/dev-/dev-$ENV/g' test to sed -i s/dev-/dev-$ENV/g test
une façon plus facile de faire cela est tout simplement de construire la chaîne avant main et de l'utiliser comme paramètre pour sed
rpstring="s/KEYWORD/$REPLACE/g"
sed -i $rpstring test.txt