Pesquisar e replace no bash usando expressões regulares

Eu vi este exemplo:

hello=ho02123ware38384you443d34o3434ingtod38384day echo ${hello//[0-9]/} 

Que segue esta syntax: ${variable//pattern/replacement}

Infelizmente, o campo pattern não parece suportar a syntax de regex completa (se eu usar . Ou \s , por exemplo, ele tenta corresponder aos caracteres literais).

Como posso pesquisar / replace uma string usando a syntax de regex completa?

Use sed :

 MYVAR=ho02123ware38384you443d34o3434ingtod38384day echo $MYVAR | sed -e 's/[a-zA-Z]/X/g' -e 's/[0-9]/N/g' # prints XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX 

Observe que os -e subseqüentes são processados ​​em ordem. Além disso, o sinalizador g da expressão corresponderá a todas as ocorrências na input.

Você também pode escolher sua ferramenta favorita usando este método, por exemplo, perl, awk, por exemplo:

 echo $MYVAR | perl -pe 's/[a-zA-Z]/X/g and s/[0-9]/N/g' 

Isso pode permitir que você faça mais correspondências criativas … Por exemplo, no recorte acima, a substituição numérica não seria usada, a menos que houvesse uma correspondência na primeira expressão (devido a lentidão and avaliação). E, claro, você tem o suporte completo de idiomas do Perl para fazer o seu lance …

Isso realmente pode ser feito em puro bash:

 hello=ho02123ware38384you443d34o3434ingtod38384day re='(.*)[0-9]+(.*)' while [[ $hello =~ $re ]]; do hello=${BASH_REMATCH[1]}${BASH_REMATCH[2]} done echo "$hello" 

…rendimentos…

 howareyoudoingtodday 

Estes exemplos também funcionam no bash sem necessidade de usar o sed:

 #!/bin/bash MYVAR=ho02123ware38384you443d34o3434ingtod38384day MYVAR=${MYVAR//[a-zA-Z]/X} echo ${MYVAR//[0-9]/N} 

você também pode usar as expressões de colchete de class de caractere

 #!/bin/bash MYVAR=ho02123ware38384you443d34o3434ingtod38384day MYVAR=${MYVAR//[[:alpha:]]/X} echo ${MYVAR//[[:digit:]]/N} 

saída

 XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX 

O que @Lanaru queria saber no entanto, se eu entendi a pergunta corretamente, é por que as extensões “full” ou PCRE \s\S\w\W\d\D etc não funcionam como suportado no php ruby ​​python etc. As extensões são de expressões regulares compatíveis com Perl (PCRE) e podem não ser compatíveis com outras formas de expressões regulares baseadas em shell.

Estes não funcionam:

 #!/bin/bash hello=ho02123ware38384you443d34o3434ingtod38384day echo ${hello//\d/} #!/bin/bash hello=ho02123ware38384you443d34o3434ingtod38384day echo $hello | sed 's/\d//g' 

saída com todos os caracteres “d” literais removidos

 ho02123ware38384you44334o3434ingto38384ay 

mas o seguinte funciona como esperado

 #!/bin/bash hello=ho02123ware38384you443d34o3434ingtod38384day echo $hello | perl -pe 's/\d//g' 

saída

 howareyoudoingtodday 

Espero que esclareça um pouco mais as coisas, mas se você ainda não está confuso, por que você não experimenta isso no Mac OS X que tem o sinalizador REG_ENHANCED habilitado:

 #!/bin/bash MYVAR=ho02123ware38384you443d34o3434ingtod38384day; echo $MYVAR | grep -o -E '\d' 

Na maioria dos sabores do * nix, você verá apenas a seguinte saída:

 d d d 

nJoy!

Use [[:digit:]] (observe os colchetes duplos) como o padrão:

 $ hello=ho02123ware38384you443d34o3434ingtod38384day $ echo ${hello//[[:digit:]]/} howareyoudoingtodday 

Só queria resumir as respostas (especialmente https://stackoverflow.com/a/22261334/2916086 do @ nickl-.

Se você está fazendo chamadas repetidas e está preocupado com o desempenho, este teste revela que o método BASH é ~ 15x mais rápido do que o pedido e provavelmente qualquer outro processo externo.

 hello=123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X123456789X P1=$(date +%s) for i in {1..10000} do echo $hello | sed s/X//g > /dev/null done P2=$(date +%s) echo $[$P2-$P1] for i in {1..10000} do echo ${hello//X/} > /dev/null done P3=$(date +%s) echo $[$P3-$P2]