Remplacement de certains caractères d'une chaîne par un autre caractère


279

J'ai une chaîne comme AxxBCyyyDEFzzLMN et je veux remplacer toutes les occurrences de x , y et z par _ .

Comment puis-je atteindre cet objectif?

Je sais que echo "$string" | tr 'x' '_' | tr 'y' '_'cela fonctionnerait, mais je veux le faire en une seule fois, sans utiliser de tuyaux.


Souhaitez-vous remplacer une séquence de x, y ou z consécutifs par un trait de soulignement, ou voulez-vous remplacer chaque x, y ou z par un trait de soulignement? Et qu'en est-il des séquences mixtes AxyzB? Trois soulignements ou un?
David Z

tr '[xyz]'remplacera [et ]aussi. L'argument doit être simplement une liste de caractères (bien que les plages comme a-zsoient correctes, et dans certaines implémentations, les classes de caractères POSIX comme [:digit:]).
tripleee

Réponses:


329
echo "$string" | tr xyz _

remplacerait chaque occurrence de x, you zpar _, donnant A__BC___DEF__LMNdans votre exemple.

echo "$string" | sed -r 's/[xyz]+/_/g'

remplacerait les occurrences répétées de x, you zpar un seul _, donnant A_BC_DEF_LMNdans votre exemple.


19
Sur Mac, j'ai obtenu ce qui suit: sed: option illégale - utilisation r: script sed [-Ealn] [extension -i] [fichier ...] sed [-Ealn] [extension -i] [-e script]. .. [-f script_file] ... [file ...]
catanore

J'ai une chaîne qui contient des ,[]{}()~caractères. Je veux le remplacer par chaque caractère spécial échappé avec '\'comment pourrais-je faire cela par oneshot?
inckka

2
@halakala Mac est livré avec une version légèrement différente de sed. Voir cette question: unix.stackexchange.com/questions/13711/… Au lieu de cela, vous pouvez installer "gnu-sed" avec le gestionnaire de paquets Homebrew puis utiliser le gsedbinaire: $ brew install gnu-sedpuis$ gsed -r 's/[xyz]+/_/g'
John Kary

6
Sur * BSD (et donc OSX), sed -Eest (fondamentalement) équivalent à sed -rde nombreuses distributions Linux, si vous utilisez, sed 's/[xyz][xyz]*/_/g'vous n'avez pas besoin de l'option. Bien sûr, cela équivaut à tr -s xyz _aucun besoin réel sedici.
tripleee

@inckka Vous ne pouvez pas l'utiliser trpour cela. sed 's/[][{}()~,]/\\&/g'mais vraiment, posez une nouvelle question si vous avez une question de suivi (n'hésitez pas à renvoyer ici pour référence, bien sûr). Soit dit en passant, ,et ~ne sont pas des métacaractères regex (bien qu'il ~soit étendu à $HOMEcertaines positions par Bash et certains autres obus; pas shcependant).
tripleee

286

Utilisation de l' expansion des paramètres Bash :

orig="AxxBCyyyDEFzzLMN"
mod=${orig//[xyz]/_}

7
Mauvaise substitution
Alexey

1
@Alexey, mon exemple fonctionne pour moi (bash 4.3.11 (1) -release). Assurez-vous que vous utilisez bash. D'autres obus peuvent ne pas fonctionner (bien que certains le fassent).
Matthew Flaschen

Merci @MatthewFlaschen. C'était exactement ce dont j'avais besoin pour remplacer sed par un chemin absolu dans un script bash (remplacer le / par \ / donc sed l'accepte).
Ryan G

1
@RyanG pourquoi utiliser sedsi bash a une substitution intégrée?
MestreLion

@MestreLion Cela a peut-être mal tourné, mais j'ai dû remplacer un nom de variable standard dans un tas de fichiers par un chemin absolu, pour lequel j'utilisais le remplacement sed inplace. mais vous ne pouvez pas avoir "/" sans y échapper dans la commande. J'enchaînais les opérations ensemble en bash. Ne serait-ce pas la meilleure façon de manipuler une chaîne en bash?
Ryan G

111

Vous pourriez trouver ce lien utile:

http://tldp.org/LDP/abs/html/string-manipulation.html

En général,

Pour remplacer la première correspondance de $ substring par $ remplacement:

${string/substring/replacement}

Pour remplacer toutes les correspondances de $ substring par $ remplacement:

${string//substring/replacement}

EDIT: Notez que cela s'applique à une variable nommée $ string.


16
Notez que cela fonctionne sur une variable nommée "chaîne" et non sur la chaîne littérale.
mattdm

1
le plus utile, car il contient une référence.
Os3

La meilleure solution et la plus courte.
northtree

8
read filename ;
sed -i 's/letter/newletter/g' "$filename" #letter

^ utilisez-en autant que vous en avez besoin et vous pouvez créer votre propre cryptage BASIC


5

Voici une solution avec l'expansion des paramètres du shell qui remplace plusieurs occurrences contiguës par une seule _:

$ var=AxxBCyyyDEFzzLMN
$ echo "${var//+([xyz])/_}"
A_BC_DEF_LMN

Notez que le modèle nécessite une correspondance de modèle étendue, activée avec+(pattern)

shopt -s extglob

Alternativement, avec l' -soption ("squeeze") de tr:

$ tr -s xyz _ <<< "$var"
A_BC_DEF_LMN
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.