如何在BASH中的替换表达式中包含正则表达式匹配?
非工作示例:
#!/bin/bash
name=joshua
echo ${name//[oa]/X\1}
我希望输出jXoshuXa
并将\1
替换为匹配的字符。
这实际上并不起作用,而是输出jX1shuX1
。
答案 0 :(得分:26)
也许并不像所有地狱那样直观且可以说是模糊不清,但是在完整性的精神中,当我们等待替换BASH捕获到达时,目前可能存在以下情况。
#!/bin/bash
name='joshua'
[[ $name =~ ([ao].*)([oa]) ]] && \
echo ${name/$BASH_REMATCH/X${BASH_REMATCH[1]}X${BASH_REMATCH[2]}}
在那个例子中,我们知道我们在寻找什么。更接近匹配所有或全局正则表达式对应物,以下示例将贪婪匹配到没有前缀X的集合的最后一次出现并继续向后直到没有剩余。
#/bin/bash
name='joshua'
while [[ $name =~ .*[^X]([oa]) ]]; do
name=${name/$BASH_REMATCH/${BASH_REMATCH:0:-1}X${BASH_REMATCH[1]}}
done
echo $name
该示例将类似于后面的表达式/(?<!X)([oa])/X\1/
,它假设只关心o和没有X前缀的字符。
两个例子的输出
jXoshuXa
的nJoy!
答案 1 :(得分:8)
bash> name=joshua
bash> echo $name | sed 's/\([oa]\)/X\1/g'
jXoshuXa
答案 2 :(得分:0)
尽管有以下要求,问题bash string substitution: reference matched subexpressions被标记为与该问题重复的内容
代码在长循环中运行,它应该是单线的,不会 启动子流程。
所以答案是:
如果您真的负担不起在子进程中启动sed,请不要使用bash!,而是使用perl,其read-update-output循环将快几倍,并且语法差异很小。 (好吧,您一定不要忘记分号。)
我切换到perl,只有一个陷阱:一台计算机上没有Unicode支持,我不得不重新安装软件包。