GNU/Linux >> Tutoriels Linux >  >> Linux

Comment s'assurer que la chaîne interpolée dans la substitution `sed` échappe à tous les métachars ?

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 que sed commande utilisant échappé chaînes (et avec le même sed 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).

En relation :Utiliser sed avec des caractères spéciaux ?
Linux
  1. Comment combiner toutes les lignes qui se terminent par un caractère barre oblique inverse ?

  2. Comment remplacer une chaîne par une chaîne contenant une barre oblique avec Sed ?

  3. Sed :Supprimer toutes les occurrences d'une chaîne, sauf la première ?

  4. Comment remplacer une chaîne dans plusieurs fichiers en ligne de commande Linux

  5. Comment déplacer tous les fichiers, y compris les fichiers cachés, dans le répertoire parent via *

Comment utiliser sed pour rechercher et remplacer une chaîne dans des fichiers

Comment utiliser Sed pour rechercher et remplacer une chaîne dans un fichier

Comment déterminez-vous la commande réelle qui vous parvient ?

Comment supprimer tous les fichiers commençant par une certaine chaîne sous Linux

Comment puis-je trouver tous les fichiers qui ne sont *pas* en écriture de groupe ?

Comment trouver des fichiers qui ne contiennent pas une chaîne de recherche donnée