Substituindo alguns caracteres em uma sequência por outro caractere

279

Eu tenho uma string como AxxBCyyyDEFzzLMN e eu quero substituir todas as ocorrências de x , y , e z com _ .

Como posso conseguir isso?

Sei que echo "$string" | tr 'x' '_' | tr 'y' '_'isso funcionaria, mas quero fazer isso de uma só vez, sem usar canos.

Amarsh
fonte
Deseja substituir qualquer sequência de x, y ou z consecutivos por um sublinhado ou deseja substituir cada x, y ou z por um sublinhado? Além disso, e sequências mistas AxyzB? Três sublinhados ou um?
David Z
tr '[xyz]'irá substituir [e ]também. O argumento deve ser simplesmente uma lista de caracteres (embora intervalos como a-zestejam corretos e, em algumas implementações, classes de caracteres POSIX como [:digit:]).
Tripleee

Respostas:

329
echo "$string" | tr xyz _

substituiria cada ocorrência de x, you zcom _, fornecendo A__BC___DEF__LMNno seu exemplo.

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

substituiria ocorrências repetidas de x, you zpor uma única _, fornecendo A_BC_DEF_LMNno seu exemplo.

jkasnicki
fonte
19
No Mac, obtive o seguinte: sed: opção ilegal - uso de r: script sed [-Ealn] [-i extension] [arquivo ...] sed [-Ealn] [-i extension] [-e script]. .. [-f script_file] ... [arquivo ...]
catanore 17/09/13
Eu tenho uma string que contém ,[]{}()~caracteres. Quero substituí-lo por cada caractere especial escapado de '\'como eu poderia fazer isso com o oneshot?
inckka
2
O @halakala Mac é enviado com uma versão ligeiramente diferente do sed. Veja esta pergunta: unix.stackexchange.com/questions/13711/... Em vez disso você pode instalar "gnu-sed" com gerenciador de pacotes Homebrew, em seguida, usar o gsedbinário: $ brew install gnu-sedentão$ gsed -r 's/[xyz]+/_/g'
John Kary
6
No * BSD (e, portanto, no OSX), sed -Eé (basicamente) equivalente a sed -rmuitas distribuições do Linux. Se você usar sed 's/[xyz][xyz]*/_/g', não precisará da opção. Claro, isso é equivalente a tr -s xyz _nenhuma necessidade real sedaqui.
tripleee
@inckka Você não pode usar trpara isso. sed 's/[][{}()~,]/\\&/g'mas, realmente, faça uma nova pergunta se você tiver uma pergunta de acompanhamento (fique à vontade para voltar aqui para referência, é claro). Aliás, ,e ~não são metacaracteres regex (embora sejam ~expandidos para $HOMEalgumas posições por Bash e outras conchas; no shentanto, não ).
Tripleee
286

Usando a expansão do parâmetro Bash :

orig="AxxBCyyyDEFzzLMN"
mod=${orig//[xyz]/_}
Matthew Flaschen
fonte
7
Substituição ruim #
Alexey
1
@ Alexey, meu exemplo funciona para mim (lançamento do bash 4.3.11 (1)). Verifique se você está usando bash. Outras conchas podem não funcionar (embora algumas funcionem).
Matthew Flaschen
Obrigado @MatthewFlaschen. Era exatamente isso que eu precisava para substituir um sed por um caminho absoluto em um script bash (substituindo o / por \ / o que o sed aceita).
Ryan G
1
@RyanG, por que usar sedse o bash possui uma substituição embutida?
MestreLion 31/01
@MestreLion Isso pode ter saído errado, mas eu precisava substituir um nome de variável padrão em um monte de arquivos por um caminho absoluto, para o qual eu estava usando a substituição sed inplace. mas você não pode ter "/" sem escapar no comando. Eu estava juntando as operações no bash. Essa não seria a melhor maneira de manipular uma string no bash?
Ryan G
111

Você pode achar este link útil:

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

Em geral,

Para substituir a primeira correspondência de $ substring por $ replace:

${string/substring/replacement}

Para substituir todas as correspondências de $ substring por $ replace:

${string//substring/replacement}

EDIT: Observe que isso se aplica a uma variável chamada $ string.

Dylan Daniels
fonte
16
Observe que isso funciona em uma variável chamada "string" e não na string literal.
mattdm
1
o mais útil, pois contém referência.
Os3 22/08/16
Melhor e mais curta solução.
northtree
8
read filename ;
sed -i 's/letter/newletter/g' "$filename" #letter

^ use quantos deles for necessário e você pode criar sua própria criptografia BASIC

Michael
fonte
5

Aqui está uma solução com expansão de parâmetro do shell que substitui várias ocorrências contíguas por uma única _:

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

Observe que o padrão requer correspondência estendida de padrão, ativada com+(pattern)

shopt -s extglob

Como alternativa, com a opção -s("squeeze") de tr:

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