我见过这个例子:
hello=ho02123ware38384you443d34o3434ingtod38384day
echo ${hello//[0-9]/}
遵循以下语法:${variable//pattern/replacement}
不幸的是,pattern
字段似乎不支持完整的正则表达式语法(例如,如果我使用.
或\s
,它会尝试匹配文字字符。)
如何使用完整的正则表达式语法搜索/替换字符串?
答案 0 :(得分:131)
使用sed:
MYVAR=ho02123ware38384you443d34o3434ingtod38384day
echo "$MYVAR" | sed -e 's/[a-zA-Z]/X/g' -e 's/[0-9]/N/g'
# prints XXNNNNNXXXXNNNNNXXXNNNXNNXNNNNXXXXXXNNNNNXXX
请注意,后续-e
按顺序处理。此外,表达式的g
标志将匹配输入中的所有匹配项。
您也可以使用此方法选择您喜欢的工具,例如perl,awk,例如:
echo "$MYVAR" | perl -pe 's/[a-zA-Z]/X/g and s/[0-9]/N/g'
这可能允许您进行更多有创意的匹配...例如,在上面的剪辑中,除非第一个表达式上存在匹配(由于惰性and
评估),否则不会使用数字替换。当然,您可以获得Perl的完整语言支持来进行出价......
答案 1 :(得分:114)
这实际上可以在纯粹的bash中完成:
hello=ho02123ware38384you443d34o3434ingtod38384day
re='(.*)[0-9]+(.*)'
while [[ $hello =~ $re ]]; do
hello=${BASH_REMATCH[1]}${BASH_REMATCH[2]}
done
echo "$hello"
... ...产量
howareyoudoingtodday
答案 2 :(得分:78)
这些示例也适用于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!
答案 3 :(得分:9)
如果您正在重复调用并且关注性能,则此测试显示BASH方法比分叉和可能的任何其他外部过程快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]
答案 4 :(得分:5)
我知道这是一个古老的话题,但这是我在Google上的第一个成功案例,我想分享我编写的以下resub
,它增加了对多个$ 1,$ 2等反向引用的支持。 ..
#!/usr/bin/env bash
############################################
### resub - regex substitution in bash ###
############################################
resub() {
local match="$1" subst="$2" tmp
if [[ -z $match ]]; then
echo "Usage: echo \"some text\" | resub '(.*) (.*)' '\$2 me \${1}time'" >&2
return 1
fi
### First, convert "$1" to "$BASH_REMATCH[1]" and 'single-quote' for later eval-ing...
### Utility function to 'single-quote' a list of strings
squot() { local a=(); for i in "$@"; do a+=( $(echo \'${i//\'/\'\"\'\"\'}\' )); done; echo "${a[@]}"; }
tmp=""
while [[ $subst =~ (.*)\${([0-9]+)}(.*) ]] || [[ $subst =~ (.*)\$([0-9]+)(.*) ]]; do
tmp="\${BASH_REMATCH[${BASH_REMATCH[2]}]}$(squot "${BASH_REMATCH[3]}")${tmp}"
subst="${BASH_REMATCH[1]}"
done
subst="$(squot "${subst}")${tmp}"
### Now start (globally) substituting
tmp=""
while read line; do
counter=0
while [[ $line =~ $match(.*) ]]; do
eval tmp='"${tmp}${line%${BASH_REMATCH[0]}}"'"${subst}"
line="${BASH_REMATCH[$(( ${#BASH_REMATCH[@]} - 1 ))]}"
done
echo "${tmp}${line}"
done
}
resub "$@"
##################
### EXAMPLES ###
##################
### % echo "The quick brown fox jumps quickly over the lazy dog" | resub quick slow
### The slow brown fox jumps slowly over the lazy dog
### % echo "The quick brown fox jumps quickly over the lazy dog" | resub 'quick ([^ ]+) fox' 'slow $1 sheep'
### The slow brown sheep jumps quickly over the lazy dog
### % animal="sheep"
### % echo "The quick brown fox 'jumps' quickly over the \"lazy\" \$dog" | resub 'quick ([^ ]+) fox' "\"\$low\" \${1} '$animal'"
### The "$low" brown 'sheep' 'jumps' quickly over the "lazy" $dog
### % echo "one two three four five" | resub "one ([^ ]+) three ([^ ]+) five" 'one $2 three $1 five'
### one four three two five
### % echo "one two one four five" | resub "one ([^ ]+) " 'XXX $1 '
### XXX two XXX four five
### % echo "one two three four five one six three seven eight" | resub "one ([^ ]+) three ([^ ]+) " 'XXX $1 YYY $2 '
### XXX two YYY four five XXX six YYY seven eight
对@Charles Duffy的H / T回复:(.*)$match(.*)
答案 5 :(得分:4)
使用[[:digit:]]
(注意双括号)作为模式:
$ hello=ho02123ware38384you443d34o3434ingtod38384day
$ echo ${hello//[[:digit:]]/}
howareyoudoingtodday
只是想总结答案(尤其是@ nickl-'s https://stackoverflow.com/a/22261334/2916086)。
答案 6 :(得分:0)
此示例在输入answer
中搜索正则表达式hello ugly world
,并将其替换为bad|ugly
nice