Reemplazar algunos caracteres en una cadena con otro carácter

279

Tengo una cadena como AxxBCyyyDEFzzLMN y quiero reemplazar todas las apariciones de x , y y z con _ .

¿Cómo puedo conseguir esto?

Sé que echo "$string" | tr 'x' '_' | tr 'y' '_'funcionaría, pero quiero hacerlo de una vez, sin usar tuberías.

Amarsh
fuente
¿Desea reemplazar cualquier secuencia de x, y's o z's consecutivas con un guión bajo, o desea reemplazar cada x, y o z con un guión bajo? Además, ¿qué pasa con las secuencias mixtas, como AxyzB? ¿Tres guiones bajos o uno?
David Z
tr '[xyz]'reemplazará [y ], también. El argumento debería ser simplemente una lista de caracteres (aunque los rangos como a-zestán bien, y en algunas implementaciones, las clases de caracteres POSIX como [:digit:]).
tripleee

Respuestas:

329
echo "$string" | tr xyz _

reemplazaría cada aparición de x, yo zcon _, dando A__BC___DEF__LMNsu ejemplo.

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

reemplazaría las repeticiones de x, yo zcon una sola _, dando A_BC_DEF_LMNen su ejemplo.

jkasnicki
fuente
19
En Mac, obtuve lo siguiente: sed: opción ilegal - uso de r: secuencia de comandos sed [-Ealn] [-i extensión] [archivo ...] sed [-Ealn] [-i extensión] [-e secuencia de comandos]. .. [-f script_file] ... [file ...]
catanore el
Tengo una cadena que contiene ,[]{}()~caracteres. Quiero reemplazarlo con cada personaje especial escapado con '\'¿cómo podría hacer esto con un disparo?
inckka
2
@halakala Mac viene con una versión ligeramente diferente de sed. Vea esta pregunta: unix.stackexchange.com/questions/13711/… En su lugar, puede instalar "gnu-sed" con el administrador de paquetes Homebrew y luego usar el gsedbinario: $ brew install gnu-sedluego$ gsed -r 's/[xyz]+/_/g'
John Kary
66
En * BSD (y, por lo tanto, OSX), sed -Ees (básicamente) equivalente a sed -ren muchas distribuciones de Linux, si usa sed 's/[xyz][xyz]*/_/g'no necesita la opción. Por supuesto, esto es equivalente a tr -s xyz _lo que no hay necesidad real de sedaquí.
tripleee
@inckka No puedes usar trpara eso. sed 's/[][{}()~,]/\\&/g'pero realmente, haga una nueva pregunta si tiene una pregunta de seguimiento (por favor, siéntase libre de vincular aquí para referencia, por supuesto). Por cierto, ,y ~no son metacaracteres regex (aunque Bash y otros shells lo ~expanden a $HOMEalgunas posiciones; sin shembargo, no ).
tripleee
286

Usando la expansión del parámetro Bash :

orig="AxxBCyyyDEFzzLMN"
mod=${orig//[xyz]/_}
Matthew Flaschen
fuente
77
Mala sustitución
Alexey
1
@Alexey, mi ejemplo funciona para mí (bash 4.3.11 (1) -release). Asegúrate de estar usando bash. Otros proyectiles podrían no funcionar (aunque algunos sí lo harán).
Matthew Flaschen
Gracias @MatthewFlaschen. Esto era exactamente lo que necesitaba para hacer un reemplazo de sed por una ruta absoluta en un script bash (reemplazando el / con \ / así sed lo acepta).
Ryan G
1
@RyanG ¿por qué usar sedsi bash tiene una sustitución incorporada?
MestreLion
@MestreLion Eso puede haber salido mal, pero necesitaba reemplazar un nombre de variable estándar en un grupo de archivos con una ruta absoluta, para lo cual estaba usando el reemplazo de sed in situ. pero no puede tener "/" sin escapar de él en el comando. Estaba encadenando las operaciones juntas en bash. ¿No sería esta la mejor manera de manipular una cadena en bash?
Ryan G
111

Puede encontrar útil este enlace:

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

En general,

Para reemplazar la primera coincidencia de $ substring con $ reemplazo:

${string/substring/replacement}

Para reemplazar todas las coincidencias de $ substring con $ reemplazo:

${string//substring/replacement}

EDITAR: tenga en cuenta que esto se aplica a una variable llamada $ string.

Dylan Daniels
fuente
16
Tenga en cuenta que esto funciona en una variable llamada "cadena" no en la cadena literal.
mattdm
1
El más útil, ya que contiene referencia.
Os3
La mejor y más corta solución.
northtree
8
read filename ;
sed -i 's/letter/newletter/g' "$filename" #letter

^ use tantos de estos como necesite, y puede hacer su propio cifrado BÁSICO

Miguel
fuente
5

Aquí hay una solución con expansión de parámetros de shell que reemplaza múltiples ocurrencias contiguas con una sola _:

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

Observe que el patrón requiere una coincidencia de patrón extendida, activada con+(pattern)

shopt -s extglob

Alternativamente, con la -sopción ("apretar") de tr:

$ tr -s xyz _ <<< "$var"
A_BC_DEF_LMN
Benjamin W.
fuente