Si vous souhaitez remplacer un mot clé par une chaîne à l'aide de sed, sed s'efforce d'interpréter votre chaîne de remplacement. Si la chaîne de remplacement contient des caractères que sed considère spéciaux, comme un caractère '/', cela échouera, à moins bien sûr que vous vouliez que votre chaîne de remplacement contienne des caractères qui indiquent à sed comment agir.
Ex:
VAR="hi/"
sed "s/KEYWORD/$VAR/g" somefile
Existe-t-il un moyen de dire à sed de ne pas essayer d'interpréter la chaîne de remplacement pour les caractères spéciaux? Tout ce que je veux, c'est pouvoir remplacer un mot-clé dans un fichier par le contenu d'une variable, quel que soit ce contenu.
bash
shell-script
sed
Tal
la source
la source
sed
et les faire ne pas être spéciaux, il suffit de les échapper.VAR='hi\/'
ne donne pas un tel problème.sed(1)
interprète simplement ce qu'il obtient. Dans votre cas, il l'obtient via une interpolation de shell. Je pense que vous ne pouvez pas faire ce que vous voulez, mais consultez le manuel. Je sais qu'en Perl (qui fait unsed
remplacement passable , avec des expressions régulières beaucoup plus riches), vous pouvez spécifier qu'une chaîne doit être prise littéralement, encore une fois, consultez le manuel.Réponses:
Il n'y a que 4 caractères spéciaux dans la pièce de rechange: \, &, et le retour à la ligne delimiter ( ref )
la source
s///
n'est pas une expression régulière, c'est vraiment juste une chaîne (sauf pour les échappements antislash et&
). Si la chaîne de remplacement est si longue, un shell one-liner n'est pas votre solution.Vous pouvez utiliser Perl au lieu de sed avec
-p
(supposer la boucle sur l'entrée) et-e
(donner le programme sur la ligne de commande). Avec Perl, vous pouvez accéder aux variables d'environnement sans les interpoler dans le shell. Notez que la variable doit être exportée :Si vous ne souhaitez pas exporter la variable partout, fournissez-la uniquement pour ce processus uniquement:
Notez que la syntaxe d'expression régulière de Perl est par défaut légèrement différente de celle de sed.
la source
PATTERN
variable d'environnement , pas dans les arguments. Dans tous les cas, cette erreur seraitE2BIG
, que vous obtiendriez également si vous l'utilisiezsed
.La solution la plus simple qui gèrerait toujours la grande majorité des valeurs de variables correctement serait d'utiliser un caractère non imprimable comme délimiteur de
sed
la commande de substitution.Dans
vi
vous pouvez échapper à n'importe quel caractère de contrôle en tapant Ctrl-V (plus communément écrit comme^V
). Donc, si vous utilisez un caractère de contrôle (j'utilise souvent^A
comme délimiteur dans ces cas), alors votresed
commande ne se cassera que si ce caractère non imprimable est présent dans la variable dans laquelle vous déposez.Vous devez donc taper
"s^V^AKEYWORD^V^A$VAR^V^Ag"
et ce que vous obtiendrez (envi
) ressemblerait à:Cela fonctionnera tant
$VAR
qu'il ne contient pas le caractère non imprimable,^A
ce qui est extrêmement improbable.Bien sûr, si vous transmettez une entrée utilisateur à la valeur de
$VAR
, tous les paris sont désactivés et vous feriez mieux de désinfecter soigneusement votre entrée plutôt que de compter sur des caractères de contrôle difficiles à taper pour l'utilisateur moyen.Cependant, il y a plus à se méfier que la chaîne de délimitation. Par exemple,
&
lorsqu'il est présent dans une chaîne de remplacement, signifie «tout le texte qui a été mis en correspondance». Par exemple,s/stu../my&/
remplacerait "stuff" par "mystuff", "piqué" par "mystung", etc. Donc, si vous pourriez avoir un caractère dans la variable que vous déposez en tant que chaîne de remplacement, mais vous voulez utiliser le littéral valeur de la variable uniquement, vous devez effectuer un nettoyage des données avant de pouvoir utiliser la variable comme chaîne de remplacement danssed
. (Le nettoyage des données peut également être effectuésed
.)la source
sed
lai
commande nsert de. Mais cesed
n'est pas un bon outil pour traiter de grandes quantités de texte de manière complexe. Je posterai une autre réponse montrant comment faire avecawk
.Vous pouvez utiliser un
,
ou un à la|
place et il le prendra comme séparateur et techniquement, vous pourriez utiliser n'importe quoidepuis la page de manuel
Comme vous pouvez le voir, vous devez commencer par un \ avant votre séparateur au début, puis vous pouvez l'utiliser comme séparateur.
à partir de la documentation http://www.gnu.org/software/sed/manual/sed.html#The-_0022s_0022-Command :
Exemple:
sed -e 'somevar|s|foo|bar|'
echo "Hello all" | sed "s_all_user_"
echo "Hello all" | sed "s,all,user,"
echo "Hello/ World" | sed "s,Hello/,Neo,"
la source
/
et il ignorera le/
bonheur comme je viens de le souligner .. en fait, vous pouvez même le chercher et le remplacer dans une chaîne >>> j'ai édité avec un exemple >>> ces les choses ne sont pas si sûres et vous trouverez toujours un mec plus intelligentsed
en premier lieu, quel est votre projet?bash
n'est PAS destiné à la manipulation de chaînes. Du tout, du tout, du tout. C'est pour la manipulation de fichiers et la coordination des commandes . Il se trouve que certaines fonctionnalités pratiques sont intégrées pour les chaînes, mais vraiment limitées et pas très rapides du tout si c'est la principale chose que vous faites. Voir "Pourquoi l'utilisation d'une boucle shell pour traiter du texte est-elle considérée comme une mauvaise pratique?" Certains outils sont conçus pour le traitement de texte sont, dans l' ordre de la plus basique à la plus puissante:sed
,awk
et Perl.S'il est basé sur une ligne et qu'une seule ligne doit être remplacée, je recommande d'ajouter le fichier lui-même avec la ligne de remplacement à l'aide de
printf
, de stocker cette première ligne danssed
l'espace de stockage de , et de la déposer si nécessaire. De cette façon, vous n'avez pas du tout à vous soucier des caractères spéciaux. (La seule hypothèse ici est que$VAR
contient une seule ligne de texte sans aucun retour à la ligne, ce que vous avez déjà dit dans les commentaires.) À part les retours à la ligne, VAR peut contenir n'importe quoi et cela fonctionnerait malgré tout.printf '%s\n'
affichera le contenu de$VAR
sous forme de chaîne littérale, quel que soit son contenu, suivi d'une nouvelle ligne. (echo
fera d'autres choses dans certains cas, par exemple si le contenu de$VAR
commence par un trait d'union — il sera interprété comme un indicateur d'option transmis àecho
.)Les accolades sont utilisées pour ajouter la sortie de
printf
au contenu desomefile
lors de sa transmissionsed
. Les espaces séparant les accolades par eux-mêmes sont importants ici, tout comme le point-virgule avant l'accolade fermante.1{h;d;};
en tant quesed
commande stockera la première ligne de texte danssed
l' espace d'attente de , puisd
supprimera la ligne (plutôt que de l'imprimer)./KEYWORD/
applique les actions suivantes à toutes les lignes qui contiennentKEYWORD
. L'action estg
et, qui récupère le contenu de l'espace d'attente et le dépose à la place de l' espace de motif - en d'autres termes, la ligne actuelle entière. (Ce n'est pas pour remplacer seulement une partie d'une ligne.) L'espace de retenue n'est pas vidé, soit dit en passant, juste copié dans l'espace de motif, remplaçant tout ce qui s'y trouve.Si vous souhaitez ancrer votre expression rationnelle afin qu'elle ne corresponde pas à une ligne qui contient simplement KEYWORD mais uniquement une ligne où il n'y a rien d'autre sur la ligne que KEYWORD, ajoutez un début d'ancre de ligne (
^
) et une ancre de fin de ligne ($
) à votre regex:la source
Vous pouvez utiliser une barre oblique inverse pour échapper aux barres obliques dans votre chaîne de remplacement, en utilisant l'expansion du paramètre de substitution de modèle de Bash. C'est un peu compliqué car les barres obliques doivent également être échappées pour Bash.
production
Vous pouvez mettre l'expansion des paramètres directement dans votre commande sed:
mais je pense que la première forme est un peu plus lisible. Et bien sûr, si vous allez réutiliser le même modèle de remplacement dans plusieurs commandes sed, il est logique de ne faire la conversion qu'une seule fois.
Une autre option serait d'utiliser un script écrit en awk, perl ou Python, ou un programme C, pour faire vos substitutions au lieu d'utiliser sed.
Voici un exemple simple en Python qui fonctionne si le mot-clé à remplacer est une ligne complète dans le fichier d'entrée (sans compter la nouvelle ligne). Comme vous pouvez le voir, il s'agit essentiellement du même algorithme que votre exemple Bash, mais il lit le fichier d'entrée plus efficacement.
la source
\x
séquences d'échappement de style. Ou d'utiliser un programme qui peut gérer des entrées arbitraires, comme je l'ai mentionné dans mon dernier paragraphe.Voici comment je suis allé:
cela fonctionne très bien dans mon cas, car mon mot clé est sur une ligne à lui tout seul. Si le mot clé était aligné avec un autre texte, cela ne fonctionnerait pas.
J'aimerais toujours vraiment savoir s'il existe un moyen facile de le faire qui n'implique pas de coder ma propre solution.
la source
echo
du tout. Utilisezprintf
plutôt. Et faire du traitement de texte dans une boucle shell est une mauvaise idée.read
est plutôt lent. Il est destiné au traitement des entrées utilisateur interactives, pas au traitement des fichiers texte. C'est lent car il lit stdin char par char, faisant un appel système pour chaque char.printf "hi\n"
fera printf imprimer une nouvelle ligne tout en l'echo "hi\n"
imprimant tel quel.printf
signifie "format" - le premier argument deprintf
est un spécificateur de format . Si ce spécificateur est%s\n
, ce qui signifie "chaîne suivie d'un saut de ligne", rien dans l'argument suivant ne sera interprété ou traduitprintf
du tout . (Le shell peut toujours l'interpréter, bien sûr; il est préférable de tout coller entre guillemets simples s'il s'agit d'une chaîne littérale, ou de guillemets doubles si vous voulez une expansion variable.) Voir ma réponse en utilisantprintf
pour plus de détails.