Comment remplacer les chaînes contenant des barres obliques par sed?

147

J'ai un projet Visual Studio, qui est développé localement. Les fichiers de code doivent être déployés sur un serveur distant. Le seul problème est que les URL qu'ils contiennent sont codées en dur.

Le projet contient des URL telles que ? Page = one . Pour que le lien soit valide sur le serveur, il doit être / page / one .

J'ai décidé de remplacer toutes les URL de mes fichiers de code par sed avant le déploiement, mais je suis bloqué sur les barres obliques.

Je sais que ce n'est pas une jolie solution, mais c'est simple qui me ferait gagner beaucoup de temps. Le nombre total de chaînes à remplacer est inférieur à 10. Le nombre total de fichiers à vérifier est de ~ 30.

Voici un exemple décrivant ma situation:

Commande que j'utilise:

sed -f replace.txt < a.txt > b.txt

replace.txt qui contient toutes les chaînes:

s/?page=one&/pageone/g
s/?page=two&/pagetwo/g
s/?page=three&/pagethree/g

a.txt:

?page=one&
?page=two&
?page=three&

Contenu de b.txt après avoir exécuté ma commande sed:

pageone
pagetwo
pagethree

Ce que je veux que b.txt contienne:

/page/one
/page/two
/page/three
afaf12
la source
1
duplication possible de la recherche sed et remplace les chaînes contenant /
Damien MATHIEU
3
duplication possible de Use slashes in sed replace
tripleee

Réponses:

274

Le moyen le plus simple serait d'utiliser un séparateur différent dans vos lignes de recherche / remplacement, par exemple:

s:?page=one&:pageone:g

Vous pouvez utiliser n'importe quel caractère comme délimiteur qui ne fait partie d'aucune chaîne. Ou, vous pouvez y échapper avec une barre oblique inverse:

s/\//foo/

Ce qui remplacerait /par foo. Vous voudrez utiliser la barre oblique inverse échappée dans les cas où vous ne savez pas quels caractères peuvent apparaître dans les chaînes de remplacement (si ce sont des variables shell, par exemple).

rôdeur
la source
1
> Ou, vous pouvez y échapper avec une barre oblique inverse. Un exemple de cela serait plus utile, car vous ne savez pas toujours quels caractères sont dans une chaîne pour pouvoir choisir quelque chose de différent. par exemple, ceci: echo / | sed s / \ // a / g ne fonctionne pas: sed: -e expression # 1, char 5: option inconnue de `s '
Max Waterman
1
Pourriez-vous en ajouter un alors? Merci :) J'ai trouvé que l'entourage entre guillemets semble fonctionner: echo / | sed "s / \ // a / g"
Max Waterman
@MaxWaterman est la procédure d'exploitation standard lors de l'utilisation sedque la commande regex est mise entre guillemets. Je ne les ai pas utilisés dans ma réponse parce que je ne montrais pas toute la sedligne de commande, mais juste la sedchaîne de commande regex comme l'avait fait l'OP. Si vous le mettez dans un fichier, comme l'a fait l'OP, vous n'avez pas besoin des guillemets.
lurker le
Ouais, assez bien (même si cela pourrait peut-être être mentionné). Cet exemple aide. J'ai constaté que je devais parfois mettre beaucoup de barres obliques inverses ... et cela devient vraiment déroutant. par exemple -e "s / '/ \\\\\\\ & / g" Je pense que le texte est faux, cependant: "Qui remplacerait \ par toto" - devrait être "Qui remplacerait / par toto", non?
Max Waterman
@MaxWaterman merci d'avoir attrapé ça sur \ vs. /. Corrigé. Si vous avez une sedcommande dans un script shell, des barres obliques inverses supplémentaires peuvent être nécessaires (chaque barre oblique inverse doit être à nouveau annulée).
lurker le
105

La scommande peut utiliser n'importe quel caractère comme délimiteur; quel que soit le caractère qui vient après que le sest utilisé. J'ai été amené à utiliser un #. Ainsi:

s#?page=one&#/page/one#g
Tom Anderson
la source
5
La page de manuel de BSD sed sous OS X dit de la commande s : Remplacez la chaîne de remplacement par la première instance de l'expression régulière dans l'espace de modèle. Tout caractère autre que la barre oblique inverse ou la nouvelle ligne peut être utilisé à la place d'une barre oblique pour délimiter l'ER et le remplacement. Je parierais que la page de manuel de GNU sed dit quelque chose de similaire.
Tom Anderson
La réponse actuellement acceptée est fondamentalement la même que celle-ci, et a été publiée une minute plus tôt!
Tom Anderson
61

Un fait très utile mais moins connu à propos de sed est que la s/foo/bar/commande familière peut utiliser n'importe quelle ponctuation, pas seulement des barres obliques. Une alternative courante est s@foo@bar@, à partir de laquelle il devient évident comment résoudre votre problème.

John Zwinck
la source
Conseil de génie lorsque vous souhaitez remplacer les barres obliques. Merci!
mbb
9

ajouter \ avant les caractères spéciaux:

s/\?page=one&/page\/one\//g

etc.

Ilja
la source
4
J'ai peut-être manqué quelque chose, mais j'ai essayé cela et cela ne semble pas fonctionner. Cela semblait évident à essayer, mais en supposant que j'ai raison et que cela ne fonctionne pas, pourquoi le publier?
codenoob
4
@codenoob (et toute autre personne qui arrive ici) - le «s» au début est requis. s/foo\/bar/foo_bar/fonctionnera, mais /foo\/bar/foo_bar/ne le fera pas.
MynockSpit
5

Dans un système que je développe, la chaîne à remplacer par sed est le texte d'entrée d'un utilisateur qui est stocké dans une variable et passé à sed.

Comme indiqué précédemment dans cet article, si la chaîne contenue dans le bloc de commande sed contient le délimiteur réel utilisé par sed - alors sed se termine sur une erreur de syntaxe. Prenons l'exemple suivant:

Cela marche:

$ VALUE=12345
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345

Cela casse:

$ VALUE=12345/6
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
sed: -e expression #1, char 21: unknown option to `s'

Le remplacement du délimiteur par défaut n'est pas une solution robuste dans mon cas car je ne voulais pas empêcher l'utilisateur de saisir des caractères spécifiques utilisés par sed comme délimiteur (par exemple "/").

Cependant, échapper à toutes les occurrences du délimiteur dans la chaîne d'entrée résoudrait le problème. Considérez la solution ci-dessous consistant à échapper systématiquement le caractère délimiteur dans la chaîne d'entrée avant de le faire analyser par sed. Un tel échappement peut être implémenté comme un remplacement en utilisant sed lui-même, ce remplacement est sûr même si la chaîne d'entrée contient le délimiteur - c'est parce que la chaîne d'entrée ne fait pas partie du bloc de commande sed:

$ VALUE=$(echo ${VALUE} | sed -e "s#/#\\\/#g")
$ echo "MyVar=%DEF_VALUE%" | sed -e s/%DEF_VALUE%/${VALUE}/g
MyVar=12345/6

J'ai converti ceci en une fonction à utiliser par divers scripts:

escapeForwardSlashes() {

     # Validate parameters
     if [ -z "$1" ]
     then
             echo -e "Error - no parameter specified!"
             return 1
     fi

     # Perform replacement
     echo ${1} | sed -e "s#/#\\\/#g"
     return 0
}
Yoav Drori
la source
1
Ce qu'il faut retenir de votre réponse pour moi, c'est que si la valeur que vous utilisez pour remplacer DEF_VALUE contient des barres obliques, vous devez les échapper avec 3 barres obliques inverses pour que sed fonctionne, par exempleVALUE="01\\\/01\\\/2018"
alexkb
3

cette ligne devrait fonctionner pour vos 3 exemples:

sed -r 's#\?(page)=([^&]*)&#/\1/\2#g' a.txt
  • J'avais l'habitude -rde sauver quelques évasions.
  • la ligne doit être générique pour votre cas un, deux trois. vous n'avez pas à faire le sous 3 fois

testez avec votre exemple (a.txt):

kent$  echo "?page=one&
?page=two&
?page=three&"|sed -r 's#\?(page)=([^&]*)&#/\1/\2#g'
/page/one
/page/two
/page/three
Kent
la source
1

replace.txt devrait être

s/?page=/\/page\//g
s/&//g
Ion Cojocaru
la source
1

Excellente réponse d'Anonyme. \ a résolu mon problème lorsque j'ai essayé d'échapper des guillemets dans des chaînes HTML.

Donc, si vous utilisez sed pour renvoyer certains modèles HTML (sur un serveur), utilisez une double barre oblique inverse au lieu d'une simple:

var htmlTemplate = "<div style=\\"color:green;\\"></div>";
Sirar Salih
la source
1

sedest le s tream ed Itor dans la mesure où vous pouvez utiliser |(tuyau) pour envoyer des flux standard (STDIN et STDOUT spécifiquement) à travers sedet de les modifier par programme à la volée, ce qui en fait un outil pratique dans la tradition de la philosophie Unix; mais peut également éditer des fichiers directement en utilisant le -iparamètre mentionné ci-dessous.
Considérez ce qui suit :

sed -i -e 's/few/asd/g' hello.txt

s/est utilisé pour s ubstituer l'expression trouvée fewavec asd:

Les rares, les courageux.


L'ASD, le courageux.

/gsignifie "global", ce qui signifie faire cela pour toute la ligne. Si vous désactivez /g(avec s/few/asd/, il doit toujours y avoir trois barres obliques quoi qu'il arrive) et fewapparaît deux fois sur la même ligne, seule la première fewest remplacée par asd:

Les quelques hommes, les quelques femmes, les courageux.


Les hommes asd, les quelques femmes, les courageux.

Ceci est utile dans certaines circonstances, comme la modification des caractères spéciaux au début des lignes (par exemple, en remplaçant les symboles plus grands que certaines personnes utilisent pour citer le matériel précédent dans les fils de discussion par une tabulation horizontale tout en laissant une inégalité algébrique citée plus tard dans la ligne intact), mais dans votre exemple où vous spécifiez que n'importe où, few il doit être remplacé, assurez-vous que/g .

Les deux options (indicateurs) suivantes sont combinées en une seule -ie:

-ioption est utilisée pour modifier i n place sur le fichier hello.txt.

-eoption indique l' e xpression / la commande à exécuter, dans ce cas s/.

Remarque: il est important que vous utilisiez -i -epour rechercher / remplacer. Si vous le faites -ie, vous créez une sauvegarde de chaque fichier avec la lettre «e» ajoutée.

Chaminda Bandara
la source
0

Une alternative plus simple consiste à utiliser AWK comme sur cette réponse :

awk '$0="prefix"$0' file > new_file

marque
la source