Cerca e sostituisci in bash usando le espressioni regolari

Ho visto questo esempio:

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

Che segue questa syntax: ${variable//pattern/replacement}

Sfortunatamente il campo pattern non sembra supportare la syntax completa dell’erghege (se io uso . O \s , ad esempio, cerca di far corrispondere i caratteri letterali).

Come posso cercare / sostituire una stringa usando la syntax completa delle espressioni regolari?

Usa sed :

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

Si noti che i successivi -e vengono elaborati in ordine. Inoltre, il flag g per l’espressione corrisponderà a tutte le occorrenze nell’input.

Puoi anche scegliere il tuo strumento preferito usando questo metodo, perl, awk, ad esempio:

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

Ciò potrebbe consentire di eseguire più corrispondenze di creatività … Ad esempio, nello snap di cui sopra, la sostituzione numerica non verrebbe utilizzata a meno che non ci fosse una corrispondenza sulla prima espressione (a causa di lazy and valutazione). E naturalmente, hai il pieno supporto linguistico di Perl per fare le tue offerte …

Questo in realtà può essere fatto in puro bash:

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

… i rendimenti …

 howareyoudoingtodday 

Questi esempi funzionano anche in bash senza bisogno di usare sed:

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

puoi anche usare le espressioni della parentesi class personaggio

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

produzione

 XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX 

Cosa volesse sapere @Lanaru, tuttavia, se ho capito bene la domanda, è perché le estensioni “complete” o PCRE \s\S\w\W\d\D ecc non funzionano come supportato in php ruby ​​python ecc. le estensioni provengono da espressioni regolari compatibili con Perl (PCRE) e potrebbero non essere compatibili con altre forms di espressioni regolari basate su shell.

Questi non funzionano:

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

uscita con tutti i caratteri letterali “d” rimossi

 ho02123ware38384you44334o3434ingto38384ay 

ma quanto segue funziona come previsto

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

produzione

 howareyoudoingtodday 

Spero che questo chiarisca un po ‘di più le cose, ma se non sei ancora confuso perché non provi questo su Mac OS X con il flag REG_ENHANCED abilitato:

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

Sulla maggior parte dei sapori di * nix vedrai solo il seguente output:

 d d d 

nJoy!

Usa [[:digit:]] (annota le parentesi doppie) come lo schema:

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

Volevo solo riassumere le risposte (in particolare @ nickl- https: //stackoverflow.com/a/22261334/2916086).

Se si effettuano chiamate ripetute e si preoccupano delle prestazioni, questo test rivela che il metodo BASH è ~ 15 volte più veloce rispetto a biforcarsi a sed e probabilmente a qualsiasi altro processo esterno.

 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]