我看过这个例子:

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

遵循以下语法:${variable//pattern/replacement}

不幸的是,模式字段似乎不支持完整的正则表达式语法(如果我使用。或者\s,例如,它试图匹配文字字符)。

我如何使用完整的正则表达式语法搜索/替换字符串?


当前回答

你可以使用python。这样做效率不高,但可以使用更灵活的语法完成工作。

申请存档

下面的pythonscript将“FROM”(而不是“notFrom”)替换为“TO”。

regex_replace.py

import sys
import re

for line in sys.stdin:
    line = re.sub(r'(?<!not)FROM', 'TO', line)
    sys.stdout.write(line)

你可以把它应用在文本文件上,比如

$ cat test.txt
bla notFROM
FROM FROM
bla bla
FROM bla

bla  notFROM FROM

bla FROM
bla bla


$ cat test.txt | python regex_replace.py
bla notFROM
TO TO
bla bla
TO bla

bla  notFROM TO

bla TO
bla bla

应用于变量

#!/bin/bash

hello=ho02123ware38384you443d34o3434ingtod38384day
echo $hello

PYTHON_CODE=$(cat <<END
import sys
import re

for line in sys.stdin:
    line = re.sub(r'[0-9]', '', line)
    sys.stdout.write(line)
END
)
echo $hello | python -c "$PYTHON_CODE"

输出

ho02123ware38384you443d34o3434ingtod38384day
howareyoudoingtodday

其他回答

如果您正在重复调用并且关心性能,这个测试显示BASH方法比分支到sed和可能的任何其他外部进程快15倍。

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]

这实际上可以在纯bash中完成:

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

收益率…

howareyoudoingtodday

你可以使用python。这样做效率不高,但可以使用更灵活的语法完成工作。

申请存档

下面的pythonscript将“FROM”(而不是“notFrom”)替换为“TO”。

regex_replace.py

import sys
import re

for line in sys.stdin:
    line = re.sub(r'(?<!not)FROM', 'TO', line)
    sys.stdout.write(line)

你可以把它应用在文本文件上,比如

$ cat test.txt
bla notFROM
FROM FROM
bla bla
FROM bla

bla  notFROM FROM

bla FROM
bla bla


$ cat test.txt | python regex_replace.py
bla notFROM
TO TO
bla bla
TO bla

bla  notFROM TO

bla TO
bla bla

应用于变量

#!/bin/bash

hello=ho02123ware38384you443d34o3434ingtod38384day
echo $hello

PYTHON_CODE=$(cat <<END
import sys
import re

for line in sys.stdin:
    line = re.sub(r'[0-9]', '', line)
    sys.stdout.write(line)
END
)
echo $hello | python -c "$PYTHON_CODE"

输出

ho02123ware38384you443d34o3434ingtod38384day
howareyoudoingtodday

使用[[:digit:]](注意双括号)作为模式:

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

只是想总结一下答案(尤其是@nickl-的https://stackoverflow.com/a/22261334/2916086)。

这些例子也可以在bash中工作,不需要使用sed:

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

也可以使用字符类括号表达式

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

输出

XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX

然而,@Lanaru想知道的是,如果我理解正确的话,为什么“完整”或PCRE扩展\s\ s\ w\ w\ d\ d等不像php、ruby、python等所支持的那样工作。这些扩展来自与perl兼容的正则表达式(PCRE),可能与其他形式的基于shell的正则表达式不兼容。

这些都不管用:

#!/bin/bash
hello=ho02123ware38384you443d34o3434ingtod38384day
echo ${hello//\d/}


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

输出时删除所有“d”字面值

ho02123ware38384you44334o3434ingto38384ay

但下面的操作确实如预期的那样工作

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

输出

howareyoudoingtodday

希望这能更清楚地说明问题,但如果你还不困惑,为什么不在启用了REG_ENHANCED标志的Mac OS X上尝试一下:

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

在大多数*nix版本中,你只会看到以下输出:

d
d
d

nJoy !