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
sedles commandes sont exécutées dans les mêmes paramètres régionaux quesedcommande utilisant échappé chaînes (et avec le mêmesedcommande) par exemple) - n'oubliez pas le caractère de nouvelle ligne (ici, vous voudrez peut-être vérifier si
$lhsen 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).