J'ai un script qui lit un flux de texte et génère un fichier de commandes sed qui est ensuite exécuté avec sed -f
. Les commandes sed générées ressemblent à :
s/cid:[email protected]/https://mysite.com/files/1922/g
s/cid:[email protected]/https://mysite.com/files/1923/g
s/cid:[email protected]/https://mysite.com/files/1924/g
Supposons que le script qui génère le sed
commandes est quelque chose comme :
while read cid fileid
do
cidpat="$(echo $cid | sed -e s/\./\\./g)"
echo 's/'"$cidpat"'/https://mysite.com/files/'"$fileid"'/g' >> sedscr
done
Comment puis-je améliorer le script pour garantir tous les métacaractères regex dans le cid
chaîne sont échappées et interpolées correctement ?
Réponse acceptée :
Pour échapper les variables à utiliser à gauche et à droite d'un s
commande dans sed
(ici $lhs
et $rhs
respectivement), vous feriez :
escaped_lhs=$(printf '%sn' "$lhs" | sed 's:[][\/.^$*]:\&:g')
escaped_rhs=$(printf '%sn' "$rhs" | sed 's:[\/&]:\&:g;$!s/$/\/')
sed "s/$escaped_lhs/$escaped_rhs/"
Notez que $lhs
ne peut pas contenir de caractère de saut de ligne.
Autrement dit, sur le LHS, échappez tous les opérateurs d'expression régulière (][.^$*
), le caractère d'échappement lui-même ( ) et le séparateur (
/
).
Sur le RHS, vous n'avez qu'à échapper &
, le séparateur, la barre oblique inverse et le caractère de nouvelle ligne (ce que vous faites en insérant une barre oblique inverse à la fin de chaque ligne sauf la dernière ($!s/$/\/
)).
Cela suppose que vous utilisez /
comme séparateur dans votre sed
s
commandes et que vous n'activez pas les Extended REs avec -r
(GNU sed
/ssed
/ast
/busybox sed
) ou -E
(BSD, ast
, GNU récent, busybox récent) ou PCREs avec -R
(ssed
) ou ER augmentés avec -A
/-X
(ast
) qui ont tous des opérateurs RE supplémentaires.
Quelques règles de base concernant les données arbitraires :
- N'utilisez pas
echo
- citez vos variables
- tenez compte de l'impact des paramètres régionaux (en particulier de son jeu de caractères :il est important que le échappement
sed
les commandes sont exécutées dans les mêmes paramètres régionaux quesed
commande utilisant échappé chaînes (et avec le mêmesed
commande) par exemple) - n'oubliez pas le caractère de nouvelle ligne (ici, vous voudrez peut-être vérifier si
$lhs
en contient et prendre des mesures).
Une autre option consiste à utiliser perl
au lieu de sed
et passez les chaînes dans l'environnement et utilisez le Q
/E
perl
Opérateurs d'expression régulière pour prendre les chaînes littéralement :
A="$lhs" B="$rhs" perl -pe 's/Q$ENV{A}E/$ENV{B}/g'
perl
(par défaut) ne sera pas affecté par le jeu de caractères des paramètres régionaux car, dans ce qui précède, il ne considère les chaînes que comme des tableaux d'octets sans se soucier des caractères (le cas échéant) qu'ils peuvent représenter pour l'utilisateur. Avec sed
, vous pouvez obtenir le même résultat en fixant les paramètres régionaux sur C
avec LC_ALL=C
pour tous les sed
commandes (bien que cela affecte également la langue des messages d'erreur, le cas échéant).